Rename Feedser to Concelier
This commit is contained in:
		| @@ -1,7 +1,7 @@ | ||||
| ````markdown | ||||
| # Feedser Vulnerability Conflict Resolution Rules | ||||
| # Concelier Vulnerability Conflict Resolution Rules | ||||
|  | ||||
| This document defines the canonical, deterministic conflict resolution strategy for merging vulnerability data from **NVD**, **GHSA**, and **OSV** in Feedser. | ||||
| This document defines the canonical, deterministic conflict resolution strategy for merging vulnerability data from **NVD**, **GHSA**, and **OSV** in Concelier. | ||||
|  | ||||
| --- | ||||
|  | ||||
| @@ -128,7 +128,7 @@ return out | ||||
|  | ||||
| ## 🧰 Optional C# Helper Class | ||||
|  | ||||
| `StellaOps.Feedser.Core/CanonicalMerger.cs` | ||||
| `StellaOps.Concelier.Core/CanonicalMerger.cs` | ||||
|  | ||||
| Implements: | ||||
|  | ||||
|   | ||||
| @@ -1,11 +1,11 @@ | ||||
| <Project> | ||||
|   <PropertyGroup> | ||||
|     <FeedserPluginOutputRoot Condition="'$(FeedserPluginOutputRoot)' == ''">$(SolutionDir)PluginBinaries</FeedserPluginOutputRoot> | ||||
|     <FeedserPluginOutputRoot Condition="'$(FeedserPluginOutputRoot)' == '' and '$(SolutionDir)' == ''">$(MSBuildThisFileDirectory)PluginBinaries</FeedserPluginOutputRoot> | ||||
|     <ConcelierPluginOutputRoot Condition="'$(ConcelierPluginOutputRoot)' == ''">$(SolutionDir)PluginBinaries</ConcelierPluginOutputRoot> | ||||
|     <ConcelierPluginOutputRoot Condition="'$(ConcelierPluginOutputRoot)' == '' and '$(SolutionDir)' == ''">$(MSBuildThisFileDirectory)PluginBinaries</ConcelierPluginOutputRoot> | ||||
|     <AuthorityPluginOutputRoot Condition="'$(AuthorityPluginOutputRoot)' == ''">$(SolutionDir)PluginBinaries\Authority</AuthorityPluginOutputRoot> | ||||
|     <AuthorityPluginOutputRoot Condition="'$(AuthorityPluginOutputRoot)' == '' and '$(SolutionDir)' == ''">$(MSBuildThisFileDirectory)PluginBinaries\Authority</AuthorityPluginOutputRoot> | ||||
|     <IsFeedserPlugin Condition="'$(IsFeedserPlugin)' == '' and $([System.String]::Copy('$(MSBuildProjectName)').StartsWith('StellaOps.Feedser.Source.'))">true</IsFeedserPlugin> | ||||
|     <IsFeedserPlugin Condition="'$(IsFeedserPlugin)' == '' and $([System.String]::Copy('$(MSBuildProjectName)').StartsWith('StellaOps.Feedser.Exporter.'))">true</IsFeedserPlugin> | ||||
|     <IsConcelierPlugin Condition="'$(IsConcelierPlugin)' == '' and $([System.String]::Copy('$(MSBuildProjectName)').StartsWith('StellaOps.Concelier.Source.'))">true</IsConcelierPlugin> | ||||
|     <IsConcelierPlugin Condition="'$(IsConcelierPlugin)' == '' and $([System.String]::Copy('$(MSBuildProjectName)').StartsWith('StellaOps.Concelier.Exporter.'))">true</IsConcelierPlugin> | ||||
|     <IsAuthorityPlugin Condition="'$(IsAuthorityPlugin)' == '' and $([System.String]::Copy('$(MSBuildProjectName)').StartsWith('StellaOps.Authority.Plugin.'))">true</IsAuthorityPlugin> | ||||
|   </PropertyGroup> | ||||
|  | ||||
| @@ -24,10 +24,10 @@ | ||||
|     <PackageReference Include="xunit" Version="2.9.2" /> | ||||
|     <PackageReference Include="xunit.runner.visualstudio" Version="2.8.2" /> | ||||
|     <PackageReference Include="Microsoft.Extensions.TimeProvider.Testing" Version="8.4.0" /> | ||||
|     <Compile Include="$(MSBuildThisFileDirectory)StellaOps.Feedser.Tests.Shared\AssemblyInfo.cs" Link="Shared\AssemblyInfo.cs" /> | ||||
|     <Compile Include="$(MSBuildThisFileDirectory)StellaOps.Feedser.Tests.Shared\MongoFixtureCollection.cs" Link="Shared\MongoFixtureCollection.cs" /> | ||||
|     <ProjectReference Include="$(MSBuildThisFileDirectory)StellaOps.Feedser.Testing\StellaOps.Feedser.Testing.csproj" /> | ||||
|     <Using Include="StellaOps.Feedser.Testing" /> | ||||
|     <Compile Include="$(MSBuildThisFileDirectory)StellaOps.Concelier.Tests.Shared\AssemblyInfo.cs" Link="Shared\AssemblyInfo.cs" /> | ||||
|     <Compile Include="$(MSBuildThisFileDirectory)StellaOps.Concelier.Tests.Shared\MongoFixtureCollection.cs" Link="Shared\MongoFixtureCollection.cs" /> | ||||
|     <ProjectReference Include="$(MSBuildThisFileDirectory)StellaOps.Concelier.Testing\StellaOps.Concelier.Testing.csproj" /> | ||||
|     <Using Include="StellaOps.Concelier.Testing" /> | ||||
|     <Using Include="Xunit" /> | ||||
|   </ItemGroup> | ||||
| </Project> | ||||
|   | ||||
| @@ -1,18 +1,18 @@ | ||||
| <Project> | ||||
|   <Target Name="FeedserCopyPluginArtifacts" AfterTargets="Build" Condition="'$(IsFeedserPlugin)' == 'true'"> | ||||
|   <Target Name="ConcelierCopyPluginArtifacts" AfterTargets="Build" Condition="'$(IsConcelierPlugin)' == 'true'"> | ||||
|     <PropertyGroup> | ||||
|       <FeedserPluginOutputDirectory>$(FeedserPluginOutputRoot)\$(MSBuildProjectName)</FeedserPluginOutputDirectory> | ||||
|       <ConcelierPluginOutputDirectory>$(ConcelierPluginOutputRoot)\$(MSBuildProjectName)</ConcelierPluginOutputDirectory> | ||||
|     </PropertyGroup> | ||||
|  | ||||
|     <MakeDir Directories="$(FeedserPluginOutputDirectory)" /> | ||||
|     <MakeDir Directories="$(ConcelierPluginOutputDirectory)" /> | ||||
|  | ||||
|     <ItemGroup> | ||||
|       <FeedserPluginArtifacts Include="$(TargetPath)" /> | ||||
|       <FeedserPluginArtifacts Include="$(TargetPath).deps.json" Condition="Exists('$(TargetPath).deps.json')" /> | ||||
|       <FeedserPluginArtifacts Include="$(TargetDir)$(TargetName).pdb" Condition="Exists('$(TargetDir)$(TargetName).pdb')" /> | ||||
|       <ConcelierPluginArtifacts Include="$(TargetPath)" /> | ||||
|       <ConcelierPluginArtifacts Include="$(TargetPath).deps.json" Condition="Exists('$(TargetPath).deps.json')" /> | ||||
|       <ConcelierPluginArtifacts Include="$(TargetDir)$(TargetName).pdb" Condition="Exists('$(TargetDir)$(TargetName).pdb')" /> | ||||
|     </ItemGroup> | ||||
|  | ||||
|     <Copy SourceFiles="@(FeedserPluginArtifacts)" DestinationFolder="$(FeedserPluginOutputDirectory)" SkipUnchangedFiles="true" /> | ||||
|     <Copy SourceFiles="@(ConcelierPluginArtifacts)" DestinationFolder="$(ConcelierPluginOutputDirectory)" SkipUnchangedFiles="true" /> | ||||
|   </Target> | ||||
|  | ||||
|   <Target Name="AuthorityCopyPluginArtifacts" AfterTargets="Build" Condition="'$(IsAuthorityPlugin)' == 'true'"> | ||||
|   | ||||
| @@ -12,15 +12,15 @@ public class StellaOpsPrincipalBuilderTests | ||||
|     public void NormalizedScopes_AreSortedDeduplicatedLowerCased() | ||||
|     { | ||||
|         var builder = new StellaOpsPrincipalBuilder() | ||||
|             .WithScopes(new[] { "Feedser.Jobs.Trigger", " feedser.jobs.trigger ", "AUTHORITY.USERS.MANAGE" }) | ||||
|             .WithAudiences(new[] { " api://feedser ", "api://cli", "api://feedser" }); | ||||
|             .WithScopes(new[] { "Concelier.Jobs.Trigger", " concelier.jobs.trigger ", "AUTHORITY.USERS.MANAGE" }) | ||||
|             .WithAudiences(new[] { " api://concelier ", "api://cli", "api://concelier" }); | ||||
|  | ||||
|         Assert.Equal( | ||||
|             new[] { "authority.users.manage", "feedser.jobs.trigger" }, | ||||
|             new[] { "authority.users.manage", "concelier.jobs.trigger" }, | ||||
|             builder.NormalizedScopes); | ||||
|  | ||||
|         Assert.Equal( | ||||
|             new[] { "api://cli", "api://feedser" }, | ||||
|             new[] { "api://cli", "api://concelier" }, | ||||
|             builder.Audiences); | ||||
|     } | ||||
|  | ||||
| @@ -38,8 +38,8 @@ public class StellaOpsPrincipalBuilderTests | ||||
|             .WithTokenId(Guid.NewGuid().ToString("N")) | ||||
|             .WithAuthenticationMethod("password") | ||||
|             .WithAuthenticationType(" custom ") | ||||
|             .WithScopes(new[] { "Feedser.Jobs.Trigger", "AUTHORITY.USERS.MANAGE" }) | ||||
|             .WithAudience(" api://feedser ") | ||||
|             .WithScopes(new[] { "Concelier.Jobs.Trigger", "AUTHORITY.USERS.MANAGE" }) | ||||
|             .WithAudience(" api://concelier ") | ||||
|             .WithIssuedAt(now) | ||||
|             .WithExpires(now.AddMinutes(5)) | ||||
|             .AddClaim(" custom ", " value "); | ||||
| @@ -57,13 +57,13 @@ public class StellaOpsPrincipalBuilderTests | ||||
|         Assert.Equal("value", principal.FindFirstValue("custom")); | ||||
|  | ||||
|         var scopeClaims = principal.Claims.Where(claim => claim.Type == StellaOpsClaimTypes.ScopeItem).Select(claim => claim.Value).ToArray(); | ||||
|         Assert.Equal(new[] { "authority.users.manage", "feedser.jobs.trigger" }, scopeClaims); | ||||
|         Assert.Equal(new[] { "authority.users.manage", "concelier.jobs.trigger" }, scopeClaims); | ||||
|  | ||||
|         var scopeList = principal.FindFirstValue(StellaOpsClaimTypes.Scope); | ||||
|         Assert.Equal("authority.users.manage feedser.jobs.trigger", scopeList); | ||||
|         Assert.Equal("authority.users.manage concelier.jobs.trigger", scopeList); | ||||
|  | ||||
|         var audienceClaims = principal.Claims.Where(claim => claim.Type == StellaOpsClaimTypes.Audience).Select(claim => claim.Value).ToArray(); | ||||
|         Assert.Equal(new[] { "api://feedser" }, audienceClaims); | ||||
|         Assert.Equal(new[] { "api://concelier" }, audienceClaims); | ||||
|  | ||||
|         var issuedAt = principal.FindFirstValue("iat"); | ||||
|         Assert.Equal(now.ToUnixTimeSeconds().ToString(), issuedAt); | ||||
|   | ||||
| @@ -37,7 +37,7 @@ public class StellaOpsProblemResultFactoryTests | ||||
|     public void InsufficientScope_AddsScopeExtensions() | ||||
|     { | ||||
|         var result = StellaOpsProblemResultFactory.InsufficientScope( | ||||
|             new[] { StellaOpsScopes.FeedserJobsTrigger }, | ||||
|             new[] { StellaOpsScopes.ConcelierJobsTrigger }, | ||||
|             new[] { StellaOpsScopes.AuthorityUsersManage }, | ||||
|             instance: "/jobs/trigger"); | ||||
|  | ||||
| @@ -46,7 +46,7 @@ public class StellaOpsProblemResultFactoryTests | ||||
|         var details = Assert.IsType<ProblemDetails>(result.ProblemDetails); | ||||
|         Assert.Equal("https://docs.stella-ops.org/problems/insufficient-scope", details.Type); | ||||
|         Assert.Equal("insufficient_scope", details.Extensions["error"]); | ||||
|         Assert.Equal(new[] { StellaOpsScopes.FeedserJobsTrigger }, Assert.IsType<string[]>(details.Extensions["required_scopes"])); | ||||
|         Assert.Equal(new[] { StellaOpsScopes.ConcelierJobsTrigger }, Assert.IsType<string[]>(details.Extensions["required_scopes"])); | ||||
|         Assert.Equal(new[] { StellaOpsScopes.AuthorityUsersManage }, Assert.IsType<string[]>(details.Extensions["granted_scopes"])); | ||||
|         Assert.Equal("/jobs/trigger", details.Instance); | ||||
|     } | ||||
|   | ||||
| @@ -9,14 +9,14 @@ namespace StellaOps.Auth.Abstractions; | ||||
| public static class StellaOpsScopes | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Scope required to trigger Feedser jobs. | ||||
|     /// Scope required to trigger Concelier jobs. | ||||
|     /// </summary> | ||||
|     public const string FeedserJobsTrigger = "feedser.jobs.trigger"; | ||||
|     public const string ConcelierJobsTrigger = "concelier.jobs.trigger"; | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Scope required to manage Feedser merge operations. | ||||
|     /// Scope required to manage Concelier merge operations. | ||||
|     /// </summary> | ||||
|     public const string FeedserMerge = "feedser.merge"; | ||||
|     public const string ConcelierMerge = "concelier.merge"; | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Scope granting administrative access to Authority user management. | ||||
| @@ -40,8 +40,8 @@ public static class StellaOpsScopes | ||||
|  | ||||
|     private static readonly HashSet<string> KnownScopes = new(StringComparer.OrdinalIgnoreCase) | ||||
|     { | ||||
|         FeedserJobsTrigger, | ||||
|         FeedserMerge, | ||||
|         ConcelierJobsTrigger, | ||||
|         ConcelierMerge, | ||||
|         AuthorityUsersManage, | ||||
|         AuthorityClientsManage, | ||||
|         AuthorityAuditRead, | ||||
|   | ||||
| @@ -15,13 +15,13 @@ public class StellaOpsAuthClientOptionsTests | ||||
|             ClientId = "cli", | ||||
|             HttpTimeout = TimeSpan.FromSeconds(15) | ||||
|         }; | ||||
|         options.DefaultScopes.Add(" Feedser.Jobs.Trigger "); | ||||
|         options.DefaultScopes.Add("feedser.jobs.trigger"); | ||||
|         options.DefaultScopes.Add(" Concelier.Jobs.Trigger "); | ||||
|         options.DefaultScopes.Add("concelier.jobs.trigger"); | ||||
|         options.DefaultScopes.Add("AUTHORITY.USERS.MANAGE"); | ||||
|  | ||||
|         options.Validate(); | ||||
|  | ||||
|         Assert.Equal(new[] { "authority.users.manage", "feedser.jobs.trigger" }, options.NormalizedScopes); | ||||
|         Assert.Equal(new[] { "authority.users.manage", "concelier.jobs.trigger" }, options.NormalizedScopes); | ||||
|         Assert.Equal(new Uri("https://authority.test"), options.AuthorityUri); | ||||
|         Assert.Equal<TimeSpan>(options.RetryDelays, options.NormalizedRetryDelays); | ||||
|     } | ||||
|   | ||||
| @@ -21,7 +21,7 @@ public class StellaOpsTokenClientTests | ||||
|         var timeProvider = new FakeTimeProvider(DateTimeOffset.Parse("2025-02-01T00:00:00Z")); | ||||
|         var responses = new Queue<HttpResponseMessage>(); | ||||
|         responses.Enqueue(CreateJsonResponse("{\"token_endpoint\":\"https://authority.test/connect/token\",\"jwks_uri\":\"https://authority.test/jwks\"}")); | ||||
|         responses.Enqueue(CreateJsonResponse("{\"access_token\":\"abc\",\"token_type\":\"Bearer\",\"expires_in\":120,\"scope\":\"feedser.jobs.trigger\"}")); | ||||
|         responses.Enqueue(CreateJsonResponse("{\"access_token\":\"abc\",\"token_type\":\"Bearer\",\"expires_in\":120,\"scope\":\"concelier.jobs.trigger\"}")); | ||||
|         responses.Enqueue(CreateJsonResponse("{\"keys\":[]}")); | ||||
|  | ||||
|         var handler = new StubHttpMessageHandler((request, cancellationToken) => | ||||
| @@ -37,7 +37,7 @@ public class StellaOpsTokenClientTests | ||||
|             Authority = "https://authority.test", | ||||
|             ClientId = "cli" | ||||
|         }; | ||||
|         options.DefaultScopes.Add("feedser.jobs.trigger"); | ||||
|         options.DefaultScopes.Add("concelier.jobs.trigger"); | ||||
|         options.Validate(); | ||||
|  | ||||
|         var optionsMonitor = new TestOptionsMonitor<StellaOpsAuthClientOptions>(options); | ||||
| @@ -49,7 +49,7 @@ public class StellaOpsTokenClientTests | ||||
|         var result = await client.RequestPasswordTokenAsync("user", "pass"); | ||||
|  | ||||
|         Assert.Equal("abc", result.AccessToken); | ||||
|         Assert.Contains("feedser.jobs.trigger", result.Scopes); | ||||
|         Assert.Contains("concelier.jobs.trigger", result.Scopes); | ||||
|  | ||||
|         await client.CacheTokenAsync("key", result.ToCacheEntry()); | ||||
|         var cached = await client.GetCachedTokenAsync("key"); | ||||
|   | ||||
| @@ -19,8 +19,8 @@ public class ServiceCollectionExtensionsTests | ||||
|             .AddInMemoryCollection(new Dictionary<string, string?> | ||||
|             { | ||||
|                 ["Authority:ResourceServer:Authority"] = "https://authority.example", | ||||
|                 ["Authority:ResourceServer:Audiences:0"] = "api://feedser", | ||||
|                 ["Authority:ResourceServer:RequiredScopes:0"] = "feedser.jobs.trigger", | ||||
|                 ["Authority:ResourceServer:Audiences:0"] = "api://concelier", | ||||
|                 ["Authority:ResourceServer:RequiredScopes:0"] = "concelier.jobs.trigger", | ||||
|                 ["Authority:ResourceServer:BypassNetworks:0"] = "127.0.0.1/32" | ||||
|             }) | ||||
|             .Build(); | ||||
| @@ -37,8 +37,8 @@ public class ServiceCollectionExtensionsTests | ||||
|         Assert.NotNull(jwtOptions.Authority); | ||||
|         Assert.Equal(new Uri("https://authority.example/"), new Uri(jwtOptions.Authority!)); | ||||
|         Assert.True(jwtOptions.TokenValidationParameters.ValidateAudience); | ||||
|         Assert.Contains("api://feedser", jwtOptions.TokenValidationParameters.ValidAudiences); | ||||
|         Assert.Contains("api://concelier", jwtOptions.TokenValidationParameters.ValidAudiences); | ||||
|         Assert.Equal(TimeSpan.FromSeconds(60), jwtOptions.TokenValidationParameters.ClockSkew); | ||||
|         Assert.Equal(new[] { "feedser.jobs.trigger" }, resourceOptions.NormalizedScopes); | ||||
|         Assert.Equal(new[] { "concelier.jobs.trigger" }, resourceOptions.NormalizedScopes); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -17,12 +17,12 @@ public class StellaOpsResourceServerOptionsTests | ||||
|             TokenClockSkew = TimeSpan.FromSeconds(30) | ||||
|         }; | ||||
|  | ||||
|         options.Audiences.Add(" api://feedser "); | ||||
|         options.Audiences.Add("api://feedser"); | ||||
|         options.Audiences.Add("api://feedser-admin"); | ||||
|         options.Audiences.Add(" api://concelier "); | ||||
|         options.Audiences.Add("api://concelier"); | ||||
|         options.Audiences.Add("api://concelier-admin"); | ||||
|  | ||||
|         options.RequiredScopes.Add(" Feedser.Jobs.Trigger "); | ||||
|         options.RequiredScopes.Add("feedser.jobs.trigger"); | ||||
|         options.RequiredScopes.Add(" Concelier.Jobs.Trigger "); | ||||
|         options.RequiredScopes.Add("concelier.jobs.trigger"); | ||||
|         options.RequiredScopes.Add("AUTHORITY.USERS.MANAGE"); | ||||
|  | ||||
|         options.BypassNetworks.Add("127.0.0.1/32"); | ||||
| @@ -32,8 +32,8 @@ public class StellaOpsResourceServerOptionsTests | ||||
|         options.Validate(); | ||||
|  | ||||
|         Assert.Equal(new Uri("https://authority.stella-ops.test"), options.AuthorityUri); | ||||
|         Assert.Equal(new[] { "api://feedser", "api://feedser-admin" }, options.Audiences); | ||||
|         Assert.Equal(new[] { "authority.users.manage", "feedser.jobs.trigger" }, options.NormalizedScopes); | ||||
|         Assert.Equal(new[] { "api://concelier", "api://concelier-admin" }, options.Audiences); | ||||
|         Assert.Equal(new[] { "authority.users.manage", "concelier.jobs.trigger" }, options.NormalizedScopes); | ||||
|         Assert.True(options.BypassMatcher.IsAllowed(IPAddress.Parse("127.0.0.1"))); | ||||
|         Assert.True(options.BypassMatcher.IsAllowed(IPAddress.IPv6Loopback)); | ||||
|     } | ||||
|   | ||||
| @@ -24,10 +24,10 @@ public class StellaOpsScopeAuthorizationHandlerTests | ||||
|         }); | ||||
|  | ||||
|         var (handler, accessor) = CreateHandler(optionsMonitor, remoteAddress: IPAddress.Parse("10.0.0.1")); | ||||
|         var requirement = new StellaOpsScopeRequirement(new[] { StellaOpsScopes.FeedserJobsTrigger }); | ||||
|         var requirement = new StellaOpsScopeRequirement(new[] { StellaOpsScopes.ConcelierJobsTrigger }); | ||||
|         var principal = new StellaOpsPrincipalBuilder() | ||||
|             .WithSubject("user-1") | ||||
|             .WithScopes(new[] { StellaOpsScopes.FeedserJobsTrigger }) | ||||
|             .WithScopes(new[] { StellaOpsScopes.ConcelierJobsTrigger }) | ||||
|             .Build(); | ||||
|  | ||||
|         var context = new AuthorizationHandlerContext(new[] { requirement }, principal, accessor.HttpContext); | ||||
| @@ -48,7 +48,7 @@ public class StellaOpsScopeAuthorizationHandlerTests | ||||
|         }); | ||||
|  | ||||
|         var (handler, accessor) = CreateHandler(optionsMonitor, remoteAddress: IPAddress.Parse("127.0.0.1")); | ||||
|         var requirement = new StellaOpsScopeRequirement(new[] { StellaOpsScopes.FeedserJobsTrigger }); | ||||
|         var requirement = new StellaOpsScopeRequirement(new[] { StellaOpsScopes.ConcelierJobsTrigger }); | ||||
|         var principal = new ClaimsPrincipal(new ClaimsIdentity()); | ||||
|         var context = new AuthorizationHandlerContext(new[] { requirement }, principal, accessor.HttpContext); | ||||
|  | ||||
| @@ -67,7 +67,7 @@ public class StellaOpsScopeAuthorizationHandlerTests | ||||
|         }); | ||||
|  | ||||
|         var (handler, accessor) = CreateHandler(optionsMonitor, remoteAddress: IPAddress.Parse("203.0.113.10")); | ||||
|         var requirement = new StellaOpsScopeRequirement(new[] { StellaOpsScopes.FeedserJobsTrigger }); | ||||
|         var requirement = new StellaOpsScopeRequirement(new[] { StellaOpsScopes.ConcelierJobsTrigger }); | ||||
|         var principal = new ClaimsPrincipal(new ClaimsIdentity()); | ||||
|         var context = new AuthorizationHandlerContext(new[] { requirement }, principal, accessor.HttpContext); | ||||
|  | ||||
|   | ||||
| @@ -4,6 +4,6 @@ ASP.NET Core helpers that enable resource servers to authenticate with **StellaO | ||||
|  | ||||
| - `AddStellaOpsResourceServerAuthentication` extension for JWT bearer + scope policies. | ||||
| - Network bypass mask evaluation for on-host automation. | ||||
| - Consistent `ProblemDetails` responses and policy helpers shared with Feedser/Backend services. | ||||
| - Consistent `ProblemDetails` responses and policy helpers shared with Concelier/Backend services. | ||||
|  | ||||
| Pair this package with `StellaOps.Auth.Abstractions` and `StellaOps.Auth.Client` for end-to-end Authority integration. | ||||
|   | ||||
| @@ -197,7 +197,7 @@ public class TokenValidationHandlersTests | ||||
|         { | ||||
|             TokenId = "token-1", | ||||
|             Status = "revoked", | ||||
|             ClientId = "feedser" | ||||
|             ClientId = "concelier" | ||||
|         }; | ||||
|  | ||||
|         var metadataAccessor = new TestRateLimiterMetadataAccessor(); | ||||
| @@ -219,7 +219,7 @@ public class TokenValidationHandlersTests | ||||
|             Request = new OpenIddictRequest() | ||||
|         }; | ||||
|  | ||||
|         var principal = CreatePrincipal("feedser", "token-1", "standard"); | ||||
|         var principal = CreatePrincipal("concelier", "token-1", "standard"); | ||||
|         var context = new OpenIddictServerEvents.ValidateTokenContext(transaction) | ||||
|         { | ||||
|             Principal = principal, | ||||
| @@ -526,7 +526,7 @@ internal static class TestHelpers | ||||
|     { | ||||
|         return new AuthorityClientDocument | ||||
|         { | ||||
|             ClientId = "feedser", | ||||
|             ClientId = "concelier", | ||||
|             ClientType = clientType, | ||||
|             SecretHash = secret is null ? null : AuthoritySecretHasher.ComputeHash(secret), | ||||
|             Plugin = "standard", | ||||
|   | ||||
| @@ -17,7 +17,7 @@ using StellaOps.Authority.Storage.Mongo.Documents; | ||||
| using StellaOps.Authority.Storage.Mongo.Extensions; | ||||
| using StellaOps.Authority.Storage.Mongo.Initialization; | ||||
| using StellaOps.Authority.Storage.Mongo.Stores; | ||||
| using StellaOps.Feedser.Testing; | ||||
| using StellaOps.Concelier.Testing; | ||||
| using StellaOps.Authority.RateLimiting; | ||||
| using StellaOps.Cryptography.Audit; | ||||
| using Xunit; | ||||
|   | ||||
| @@ -30,10 +30,10 @@ public class AuthorityRateLimiterIntegrationTests | ||||
|         using var client = server.CreateClient(); | ||||
|         client.DefaultRequestHeaders.Add("X-Forwarded-For", "198.51.100.50"); | ||||
|  | ||||
|         var firstResponse = await client.PostAsync("/token", CreateTokenForm("feedser")); | ||||
|         var firstResponse = await client.PostAsync("/token", CreateTokenForm("concelier")); | ||||
|         Assert.Equal(HttpStatusCode.OK, firstResponse.StatusCode); | ||||
|  | ||||
|         var secondResponse = await client.PostAsync("/token", CreateTokenForm("feedser")); | ||||
|         var secondResponse = await client.PostAsync("/token", CreateTokenForm("concelier")); | ||||
|         Assert.Equal(HttpStatusCode.TooManyRequests, secondResponse.StatusCode); | ||||
|         Assert.NotNull(secondResponse.Headers.RetryAfter); | ||||
|     } | ||||
|   | ||||
| @@ -25,17 +25,17 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Configuration", " | ||||
| EndProject | ||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Authority.Plugins.Abstractions.Tests", "StellaOps.Authority.Plugins.Abstractions.Tests\StellaOps.Authority.Plugins.Abstractions.Tests.csproj", "{EE97137B-22AF-4A84-9F65-9B4C6468B3CF}" | ||||
| EndProject | ||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Feedser.Testing", "..\StellaOps.Feedser.Testing\StellaOps.Feedser.Testing.csproj", "{D48E48BF-80C8-43DA-8BE6-E2B9E769C49E}" | ||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Testing", "..\StellaOps.Concelier.Testing\StellaOps.Concelier.Testing.csproj", "{D48E48BF-80C8-43DA-8BE6-E2B9E769C49E}" | ||||
| EndProject | ||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Feedser.Source.Common", "..\StellaOps.Feedser.Source.Common\StellaOps.Feedser.Source.Common.csproj", "{E0B9CD7A-C4FF-44EB-BE04-9B998C1C4166}" | ||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Source.Common", "..\StellaOps.Concelier.Source.Common\StellaOps.Concelier.Source.Common.csproj", "{E0B9CD7A-C4FF-44EB-BE04-9B998C1C4166}" | ||||
| EndProject | ||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Feedser.Storage.Mongo", "..\StellaOps.Feedser.Storage.Mongo\StellaOps.Feedser.Storage.Mongo.csproj", "{67C85AC6-1670-4A0D-A81F-6015574F46C7}" | ||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Storage.Mongo", "..\StellaOps.Concelier.Storage.Mongo\StellaOps.Concelier.Storage.Mongo.csproj", "{67C85AC6-1670-4A0D-A81F-6015574F46C7}" | ||||
| EndProject | ||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Feedser.Core", "..\StellaOps.Feedser.Core\StellaOps.Feedser.Core.csproj", "{17829125-C0F5-47E6-A16C-EC142BD58220}" | ||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Core", "..\StellaOps.Concelier.Core\StellaOps.Concelier.Core.csproj", "{17829125-C0F5-47E6-A16C-EC142BD58220}" | ||||
| EndProject | ||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Feedser.Models", "..\StellaOps.Feedser.Models\StellaOps.Feedser.Models.csproj", "{9B4BA030-C979-4191-8B4F-7E2AD9F88A94}" | ||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Models", "..\StellaOps.Concelier.Models\StellaOps.Concelier.Models.csproj", "{9B4BA030-C979-4191-8B4F-7E2AD9F88A94}" | ||||
| EndProject | ||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Feedser.Normalization", "..\StellaOps.Feedser.Normalization\StellaOps.Feedser.Normalization.csproj", "{26B58A9B-DB0B-4E3D-9827-3722859E5FB4}" | ||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Normalization", "..\StellaOps.Concelier.Normalization\StellaOps.Concelier.Normalization.csproj", "{26B58A9B-DB0B-4E3D-9827-3722859E5FB4}" | ||||
| EndProject | ||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Authority.Tests", "StellaOps.Authority.Tests\StellaOps.Authority.Tests.csproj", "{D719B01C-2424-4DAB-94B9-C9B6004F450B}" | ||||
| EndProject | ||||
|   | ||||
| @@ -15,7 +15,7 @@ | ||||
| > Remark (2025-10-14): Background sweep emits invite expiry audits; integration test added. | ||||
| | SEC5.HOST-REPLAY | DONE (2025-10-14) | Security Guild, Zastava | SEC5.E | Persist token usage metadata and surface suspected replay heuristics. | ✅ Validation handlers record device metadata; ✅ Suspected replay flagged via audit/logs; ✅ Tests cover regression cases. | | ||||
| > Remark (2025-10-14): Token validation handler logs suspected replay audits with device metadata; coverage via unit/integration tests. | ||||
| | SEC3.BUILD | DONE (2025-10-11) | Authority Core, Security Guild | SEC3.HOST, FEEDMERGE-COORD-02-900 | Track normalized-range dependency fallout and restore full test matrix once Feedser range primitives land. | ✅ Feedser normalized range libraries merged; ✅ Authority + Configuration test suites (`dotnet test src/StellaOps.Authority.sln`, `dotnet test src/StellaOps.Configuration.Tests/StellaOps.Configuration.Tests.csproj`) pass without Feedser compile failures; ✅ Status recorded here/Sprints (authority-core broadcast not available). | | ||||
| | SEC3.BUILD | DONE (2025-10-11) | Authority Core, Security Guild | SEC3.HOST, FEEDMERGE-COORD-02-900 | Track normalized-range dependency fallout and restore full test matrix once Concelier range primitives land. | ✅ Concelier normalized range libraries merged; ✅ Authority + Configuration test suites (`dotnet test src/StellaOps.Authority.sln`, `dotnet test src/StellaOps.Configuration.Tests/StellaOps.Configuration.Tests.csproj`) pass without Concelier compile failures; ✅ Status recorded here/Sprints (authority-core broadcast not available). | | ||||
| | AUTHCORE-BUILD-OPENIDDICT | DONE (2025-10-14) | Authority Core | SEC2.HOST | Adapt host/audit handlers for OpenIddict 6.4 API surface (no `OpenIddictServerTransaction`) and restore Authority solution build. | ✅ Build `dotnet build src/StellaOps.Authority.sln` succeeds; ✅ Audit correlation + tamper logging verified under new abstractions; ✅ Tests updated. | | ||||
| | AUTHCORE-STORAGE-DEVICE-TOKENS | DONE (2025-10-14) | Authority Core, Storage Guild | AUTHCORE-BUILD-OPENIDDICT | Reintroduce `AuthorityTokenDeviceDocument` + projections removed during refactor so storage layer compiles. | ✅ Document type restored with mappings/migrations; ✅ Storage tests cover device artifacts; ✅ Authority solution build green. | | ||||
| | AUTHCORE-BOOTSTRAP-INVITES | DONE (2025-10-14) | Authority Core, DevOps | AUTHCORE-STORAGE-DEVICE-TOKENS | Wire bootstrap invite cleanup service against restored document schema and re-enable lifecycle tests. | ✅ `BootstrapInviteCleanupService` passes integration tests; ✅ Operator guide updated if behavior changes; ✅ Build/test matrices green. | | ||||
|   | ||||
| @@ -128,7 +128,7 @@ public sealed class CommandHandlersTests | ||||
|                     Url = "https://authority.example", | ||||
|                     ClientId = "cli", | ||||
|                     ClientSecret = "secret", | ||||
|                     Scope = "feedser.jobs.trigger", | ||||
|                     Scope = "concelier.jobs.trigger", | ||||
|                     TokenCacheDirectory = tempDir.Path | ||||
|                 } | ||||
|             }; | ||||
| @@ -263,7 +263,7 @@ public sealed class CommandHandlersTests | ||||
|                 "token", | ||||
|                 "Bearer", | ||||
|                 DateTimeOffset.UtcNow.AddMinutes(30), | ||||
|                 new[] { StellaOpsScopes.FeedserJobsTrigger }); | ||||
|                 new[] { StellaOpsScopes.ConcelierJobsTrigger }); | ||||
|  | ||||
|             var provider = BuildServiceProvider(new StubBackendClient(new JobTriggerResult(true, "ok", null, null)), options: options, tokenClient: tokenClient); | ||||
|  | ||||
| @@ -331,13 +331,13 @@ public sealed class CommandHandlersTests | ||||
|             tokenClient.CachedEntry = new StellaOpsTokenCacheEntry( | ||||
|                 CreateUnsignedJwt( | ||||
|                     ("sub", "cli-user"), | ||||
|                     ("aud", "feedser"), | ||||
|                     ("aud", "concelier"), | ||||
|                     ("iss", "https://authority.example"), | ||||
|                     ("iat", 1_700_000_000), | ||||
|                     ("nbf", 1_700_000_000)), | ||||
|                 "Bearer", | ||||
|                 DateTimeOffset.UtcNow.AddMinutes(30), | ||||
|                 new[] { StellaOpsScopes.FeedserJobsTrigger }); | ||||
|                 new[] { StellaOpsScopes.ConcelierJobsTrigger }); | ||||
|  | ||||
|             var provider = BuildServiceProvider(new StubBackendClient(new JobTriggerResult(true, "ok", null, null)), options: options, tokenClient: tokenClient); | ||||
|  | ||||
| @@ -375,7 +375,7 @@ public sealed class CommandHandlersTests | ||||
|                 "token", | ||||
|                 "Bearer", | ||||
|                 DateTimeOffset.UtcNow.AddMinutes(5), | ||||
|                 new[] { StellaOpsScopes.FeedserJobsTrigger }); | ||||
|                 new[] { StellaOpsScopes.ConcelierJobsTrigger }); | ||||
|  | ||||
|             var provider = BuildServiceProvider(new StubBackendClient(new JobTriggerResult(true, "ok", null, null)), options: options, tokenClient: tokenClient); | ||||
|  | ||||
| @@ -573,7 +573,7 @@ public sealed class CommandHandlersTests | ||||
|                 "token-123", | ||||
|                 "Bearer", | ||||
|                 DateTimeOffset.UtcNow.AddMinutes(30), | ||||
|                 new[] { StellaOpsScopes.FeedserJobsTrigger }); | ||||
|                 new[] { StellaOpsScopes.ConcelierJobsTrigger }); | ||||
|         } | ||||
|  | ||||
|         public int ClientCredentialRequests { get; private set; } | ||||
|   | ||||
| @@ -24,7 +24,7 @@ public sealed class CliBootstrapperTests : IDisposable | ||||
|         Environment.SetEnvironmentVariable("STELLAOPS_BACKEND_URL", "https://env-backend.example"); | ||||
|         Environment.SetEnvironmentVariable("STELLAOPS_AUTHORITY_URL", "https://authority.env"); | ||||
|         Environment.SetEnvironmentVariable("STELLAOPS_AUTHORITY_CLIENT_ID", "cli-env"); | ||||
|         Environment.SetEnvironmentVariable("STELLAOPS_AUTHORITY_SCOPE", "feedser.jobs.trigger"); | ||||
|         Environment.SetEnvironmentVariable("STELLAOPS_AUTHORITY_SCOPE", "concelier.jobs.trigger"); | ||||
|         Environment.SetEnvironmentVariable("STELLAOPS_AUTHORITY_ENABLE_RETRIES", "false"); | ||||
|         Environment.SetEnvironmentVariable("STELLAOPS_AUTHORITY_RETRY_DELAYS", "00:00:02,00:00:05"); | ||||
|         Environment.SetEnvironmentVariable("STELLAOPS_AUTHORITY_ALLOW_OFFLINE_CACHE_FALLBACK", "false"); | ||||
| @@ -38,7 +38,7 @@ public sealed class CliBootstrapperTests : IDisposable | ||||
|             Assert.Equal("https://env-backend.example", options.BackendUrl); | ||||
|             Assert.Equal("https://authority.env", options.Authority.Url); | ||||
|             Assert.Equal("cli-env", options.Authority.ClientId); | ||||
|             Assert.Equal("feedser.jobs.trigger", options.Authority.Scope); | ||||
|             Assert.Equal("concelier.jobs.trigger", options.Authority.Scope); | ||||
|  | ||||
|             Assert.NotNull(options.Authority.Resilience); | ||||
|             Assert.False(options.Authority.Resilience.EnableRetries); | ||||
| @@ -73,7 +73,7 @@ public sealed class CliBootstrapperTests : IDisposable | ||||
|                 { | ||||
|                     Url = "https://authority.file", | ||||
|                     ClientId = "cli-file", | ||||
|                     Scope = "feedser.jobs.trigger" | ||||
|                     Scope = "concelier.jobs.trigger" | ||||
|                 } | ||||
|             } | ||||
|         }); | ||||
|   | ||||
| @@ -46,12 +46,12 @@ public sealed class BackendOperationsClientTests | ||||
|  | ||||
|         var httpClient = new HttpClient(handler) | ||||
|         { | ||||
|             BaseAddress = new Uri("https://feedser.example") | ||||
|             BaseAddress = new Uri("https://concelier.example") | ||||
|         }; | ||||
|  | ||||
|         var options = new StellaOpsCliOptions | ||||
|         { | ||||
|             BackendUrl = "https://feedser.example", | ||||
|             BackendUrl = "https://concelier.example", | ||||
|             ScannerCacheDirectory = temp.Path, | ||||
|             ScannerDownloadAttempts = 1 | ||||
|         }; | ||||
| @@ -92,12 +92,12 @@ public sealed class BackendOperationsClientTests | ||||
|  | ||||
|         var httpClient = new HttpClient(handler) | ||||
|         { | ||||
|             BaseAddress = new Uri("https://feedser.example") | ||||
|             BaseAddress = new Uri("https://concelier.example") | ||||
|         }; | ||||
|  | ||||
|         var options = new StellaOpsCliOptions | ||||
|         { | ||||
|             BackendUrl = "https://feedser.example", | ||||
|             BackendUrl = "https://concelier.example", | ||||
|             ScannerCacheDirectory = temp.Path, | ||||
|             ScannerDownloadAttempts = 1 | ||||
|         }; | ||||
| @@ -144,12 +144,12 @@ public sealed class BackendOperationsClientTests | ||||
|  | ||||
|         var httpClient = new HttpClient(handler) | ||||
|         { | ||||
|             BaseAddress = new Uri("https://feedser.example") | ||||
|             BaseAddress = new Uri("https://concelier.example") | ||||
|         }; | ||||
|  | ||||
|         var options = new StellaOpsCliOptions | ||||
|         { | ||||
|             BackendUrl = "https://feedser.example", | ||||
|             BackendUrl = "https://concelier.example", | ||||
|             ScannerCacheDirectory = temp.Path, | ||||
|             ScannerDownloadAttempts = 3 | ||||
|         }; | ||||
| @@ -196,12 +196,12 @@ public sealed class BackendOperationsClientTests | ||||
|  | ||||
|         var httpClient = new HttpClient(handler) | ||||
|         { | ||||
|             BaseAddress = new Uri("https://feedser.example") | ||||
|             BaseAddress = new Uri("https://concelier.example") | ||||
|         }; | ||||
|  | ||||
|         var options = new StellaOpsCliOptions | ||||
|         { | ||||
|             BackendUrl = "https://feedser.example", | ||||
|             BackendUrl = "https://concelier.example", | ||||
|             ScanUploadAttempts = 3 | ||||
|         }; | ||||
|  | ||||
| @@ -234,12 +234,12 @@ public sealed class BackendOperationsClientTests | ||||
|  | ||||
|         var httpClient = new HttpClient(handler) | ||||
|         { | ||||
|             BaseAddress = new Uri("https://feedser.example") | ||||
|             BaseAddress = new Uri("https://concelier.example") | ||||
|         }; | ||||
|  | ||||
|         var options = new StellaOpsCliOptions | ||||
|         { | ||||
|             BackendUrl = "https://feedser.example", | ||||
|             BackendUrl = "https://concelier.example", | ||||
|             ScanUploadAttempts = 2 | ||||
|         }; | ||||
|  | ||||
| @@ -273,10 +273,10 @@ public sealed class BackendOperationsClientTests | ||||
|  | ||||
|         var httpClient = new HttpClient(handler) | ||||
|         { | ||||
|             BaseAddress = new Uri("https://feedser.example") | ||||
|             BaseAddress = new Uri("https://concelier.example") | ||||
|         }; | ||||
|  | ||||
|         var options = new StellaOpsCliOptions { BackendUrl = "https://feedser.example" }; | ||||
|         var options = new StellaOpsCliOptions { BackendUrl = "https://concelier.example" }; | ||||
|         var loggerFactory = LoggerFactory.Create(builder => builder.SetMinimumLevel(LogLevel.Debug)); | ||||
|         var client = new BackendOperationsClient(httpClient, options, loggerFactory.CreateLogger<BackendOperationsClient>()); | ||||
|  | ||||
| @@ -308,10 +308,10 @@ public sealed class BackendOperationsClientTests | ||||
|  | ||||
|         var httpClient = new HttpClient(handler) | ||||
|         { | ||||
|             BaseAddress = new Uri("https://feedser.example") | ||||
|             BaseAddress = new Uri("https://concelier.example") | ||||
|         }; | ||||
|  | ||||
|         var options = new StellaOpsCliOptions { BackendUrl = "https://feedser.example" }; | ||||
|         var options = new StellaOpsCliOptions { BackendUrl = "https://concelier.example" }; | ||||
|         var loggerFactory = LoggerFactory.Create(builder => builder.SetMinimumLevel(LogLevel.Debug)); | ||||
|         var client = new BackendOperationsClient(httpClient, options, loggerFactory.CreateLogger<BackendOperationsClient>()); | ||||
|  | ||||
| @@ -348,18 +348,18 @@ public sealed class BackendOperationsClientTests | ||||
|  | ||||
|         var httpClient = new HttpClient(handler) | ||||
|         { | ||||
|             BaseAddress = new Uri("https://feedser.example") | ||||
|             BaseAddress = new Uri("https://concelier.example") | ||||
|         }; | ||||
|  | ||||
|         var options = new StellaOpsCliOptions | ||||
|         { | ||||
|             BackendUrl = "https://feedser.example", | ||||
|             BackendUrl = "https://concelier.example", | ||||
|             Authority = | ||||
|             { | ||||
|                 Url = "https://authority.example", | ||||
|                 ClientId = "cli", | ||||
|                 ClientSecret = "secret", | ||||
|                 Scope = "feedser.jobs.trigger", | ||||
|                 Scope = "concelier.jobs.trigger", | ||||
|                 TokenCacheDirectory = temp.Path | ||||
|             } | ||||
|         }; | ||||
| @@ -387,7 +387,7 @@ public sealed class BackendOperationsClientTests | ||||
|                 "token-123", | ||||
|                 "Bearer", | ||||
|                 DateTimeOffset.UtcNow.AddMinutes(5), | ||||
|                 new[] { StellaOpsScopes.FeedserJobsTrigger }); | ||||
|                 new[] { StellaOpsScopes.ConcelierJobsTrigger }); | ||||
|         } | ||||
|  | ||||
|         public ValueTask CacheTokenAsync(string key, StellaOpsTokenCacheEntry entry, CancellationToken cancellationToken = default) | ||||
|   | ||||
| @@ -1,14 +1,14 @@ | ||||
| # StellaOps.Cli — Agent Brief | ||||
|  | ||||
| ## Mission | ||||
| - Deliver an offline-capable command-line interface that drives StellaOps back-end operations: scanner distribution, scan execution, result uploads, and Feedser database lifecycle calls (init/resume/export). | ||||
| - Deliver an offline-capable command-line interface that drives StellaOps back-end operations: scanner distribution, scan execution, result uploads, and Concelier database lifecycle calls (init/resume/export). | ||||
| - Honour StellaOps principles of determinism, observability, and offline-first behaviour while providing a polished operator experience. | ||||
|  | ||||
| ## Role Charter | ||||
| | Role | Mandate | Collaboration | | ||||
| | --- | --- | --- | | ||||
| | **DevEx/CLI** | Own CLI UX, command routing, and configuration model. Ensure commands work with empty/default config and document overrides. | Coordinate with Backend/WebService for API contracts and with Docs for operator workflows. | | ||||
| | **Ops Integrator** | Maintain integration paths for shell/dotnet/docker tooling. Validate that air-gapped runners can bootstrap required binaries. | Work with Feedser/Agent teams to mirror packaging and signing requirements. | | ||||
| | **Ops Integrator** | Maintain integration paths for shell/dotnet/docker tooling. Validate that air-gapped runners can bootstrap required binaries. | Work with Concelier/Agent teams to mirror packaging and signing requirements. | | ||||
| | **QA** | Provide command-level fixtures, golden outputs, and regression coverage (unit & smoke). Ensure commands respect cancellation and deterministic logging. | Partner with QA guild for shared harnesses and test data. | | ||||
|  | ||||
| ## Working Agreements | ||||
| @@ -21,7 +21,7 @@ | ||||
| - Update `TASKS.md` as states change (TODO → DOING → DONE/BLOCKED) and record added tests/fixtures alongside implementation notes. | ||||
|  | ||||
| ## Reference Materials | ||||
| - `docs/ARCHITECTURE_FEEDSER.md` for database operations surface area. | ||||
| - `docs/ARCHITECTURE_CONCELIER.md` for database operations surface area. | ||||
| - Backend OpenAPI/contract docs (once available) for job triggers and scanner endpoints. | ||||
| - Existing module AGENTS/TASKS files for style and coordination cues. | ||||
| - `docs/09_API_CLI_REFERENCE.md` (section 3) for the user-facing synopsis of the CLI verbs and flags. | ||||
|   | ||||
| @@ -137,7 +137,7 @@ internal static class CommandFactory | ||||
|  | ||||
|     private static Command BuildDatabaseCommand(IServiceProvider services, Option<bool> verboseOption, CancellationToken cancellationToken) | ||||
|     { | ||||
|         var db = new Command("db", "Trigger Feedser database operations via backend jobs."); | ||||
|         var db = new Command("db", "Trigger Concelier database operations via backend jobs."); | ||||
|  | ||||
|         var fetch = new Command("fetch", "Trigger connector fetch/parse/map stages."); | ||||
|         var sourceOption = new Option<string>("--source") | ||||
| @@ -174,7 +174,7 @@ internal static class CommandFactory | ||||
|             return CommandHandlers.HandleMergeJobAsync(services, verbose, cancellationToken); | ||||
|         }); | ||||
|  | ||||
|         var export = new Command("export", "Run Feedser export jobs."); | ||||
|         var export = new Command("export", "Run Concelier export jobs."); | ||||
|         var formatOption = new Option<string>("--format") | ||||
|         { | ||||
|             Description = "Export format: json or trivy-db." | ||||
|   | ||||
| @@ -11,7 +11,7 @@ internal static class AuthorityTokenUtilities | ||||
|  | ||||
|         var scope = options.Authority?.Scope; | ||||
|         return string.IsNullOrWhiteSpace(scope) | ||||
|             ? StellaOpsScopes.FeedserJobsTrigger | ||||
|             ? StellaOpsScopes.ConcelierJobsTrigger | ||||
|             : scope.Trim(); | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -113,7 +113,7 @@ public static class CliBootstrapper | ||||
|                 authority.ClientSecret = string.IsNullOrWhiteSpace(authority.ClientSecret) ? null : authority.ClientSecret.Trim(); | ||||
|                 authority.Username = authority.Username?.Trim() ?? string.Empty; | ||||
|                 authority.Password = string.IsNullOrWhiteSpace(authority.Password) ? null : authority.Password.Trim(); | ||||
|                 authority.Scope = string.IsNullOrWhiteSpace(authority.Scope) ? StellaOpsScopes.FeedserJobsTrigger : authority.Scope.Trim(); | ||||
|                 authority.Scope = string.IsNullOrWhiteSpace(authority.Scope) ? StellaOpsScopes.ConcelierJobsTrigger : authority.Scope.Trim(); | ||||
|  | ||||
|                 authority.Resilience ??= new StellaOpsCliAuthorityResilienceOptions(); | ||||
|                 authority.Resilience.RetryDelays ??= new List<TimeSpan>(); | ||||
|   | ||||
| @@ -37,7 +37,7 @@ public sealed class StellaOpsCliAuthorityOptions | ||||
|  | ||||
|     public string? Password { get; set; } | ||||
|  | ||||
|     public string Scope { get; set; } = StellaOpsScopes.FeedserJobsTrigger; | ||||
|     public string Scope { get; set; } = StellaOpsScopes.ConcelierJobsTrigger; | ||||
|  | ||||
|     public string TokenCacheDirectory { get; set; } = string.Empty; | ||||
|  | ||||
|   | ||||
| @@ -46,7 +46,7 @@ internal static class Program | ||||
|                 clientOptions.ClientSecret = options.Authority.ClientSecret; | ||||
|                 clientOptions.DefaultScopes.Clear(); | ||||
|                 clientOptions.DefaultScopes.Add(string.IsNullOrWhiteSpace(options.Authority.Scope) | ||||
|                     ? StellaOps.Auth.Abstractions.StellaOpsScopes.FeedserJobsTrigger | ||||
|                     ? StellaOps.Auth.Abstractions.StellaOpsScopes.ConcelierJobsTrigger | ||||
|                     : options.Authority.Scope); | ||||
|  | ||||
|                 var resilience = options.Authority.Resilience ?? new StellaOpsCliAuthorityResilienceOptions(); | ||||
|   | ||||
| @@ -6,7 +6,7 @@ If you are working on this file you need to read docs/ARCHITECTURE_EXCITITOR.md | ||||
| |Introduce command host & routing skeleton|DevEx/CLI|Configuration|**DONE** – System.CommandLine (v2.0.0-beta5) router stitched with `scanner`, `scan`, `db`, and `config` verbs.| | ||||
| |Scanner artifact download/install commands|Ops Integrator|Backend contracts|**DONE** – `scanner download` caches bundles, validates SHA-256 (plus optional RSA signature), installs via `docker load`, persists metadata, and retries with exponential backoff.| | ||||
| |Scan execution & result upload workflow|Ops Integrator, QA|Scanner cmd|**DONE** – `scan run` drives container scans against directories, emits artefacts in `ResultsDirectory`, auto-uploads on success, and `scan upload` covers manual retries.| | ||||
| |Feedser DB operations passthrough|DevEx/CLI|Backend, Feedser APIs|**DONE** – `db fetch|merge|export` trigger `/jobs/*` endpoints with parameter binding and consistent exit codes.| | ||||
| |Concelier DB operations passthrough|DevEx/CLI|Backend, Concelier APIs|**DONE** – `db fetch|merge|export` trigger `/jobs/*` endpoints with parameter binding and consistent exit codes.| | ||||
| |CLI observability & tests|QA|Command host|**DONE** – Added console logging defaults & configuration bootstrap tests; future metrics hooks tracked separately.| | ||||
| |Authority auth commands|DevEx/CLI|Auth libraries|**DONE** – `auth login/logout/status` wrap the shared auth client, manage token cache, and surface status messages.| | ||||
| |Document authority workflow in CLI help & quickstart|Docs/CLI|Authority auth commands|**DONE (2025-10-10)** – CLI help now surfaces Authority config fields and docs/09 + docs/10 describe env vars, auth login/status flow, and cache location.| | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| using StellaOps.Feedser.Models; | ||||
| using StellaOps.Concelier.Models; | ||||
| 
 | ||||
| namespace StellaOps.Feedser.Core.Tests; | ||||
| namespace StellaOps.Concelier.Core.Tests; | ||||
| 
 | ||||
| public sealed class CanonicalMergerTests | ||||
| { | ||||
| @@ -4,9 +4,9 @@ using System.Linq; | ||||
| using Microsoft.Extensions.DependencyInjection; | ||||
| using Microsoft.Extensions.Logging.Abstractions; | ||||
| using Microsoft.Extensions.Options; | ||||
| using StellaOps.Feedser.Core.Jobs; | ||||
| using StellaOps.Concelier.Core.Jobs; | ||||
| 
 | ||||
| namespace StellaOps.Feedser.Core.Tests; | ||||
| namespace StellaOps.Concelier.Core.Tests; | ||||
| 
 | ||||
| public sealed class JobCoordinatorTests | ||||
| { | ||||
| @@ -4,10 +4,10 @@ using System.IO; | ||||
| using Microsoft.Extensions.Configuration; | ||||
| using Microsoft.Extensions.DependencyInjection; | ||||
| using Microsoft.Extensions.Options; | ||||
| using StellaOps.Feedser.Core.Jobs; | ||||
| using StellaOps.Concelier.Core.Jobs; | ||||
| using StellaOps.Plugin.Hosting; | ||||
| 
 | ||||
| namespace StellaOps.Feedser.Core.Tests; | ||||
| namespace StellaOps.Concelier.Core.Tests; | ||||
| 
 | ||||
| public sealed class JobPluginRegistrationExtensionsTests | ||||
| { | ||||
| @@ -53,7 +53,7 @@ public sealed class JobPluginRegistrationExtensionsTests | ||||
|         Assert.True(schedulerOptions.Definitions.TryGetValue(PluginJob.JobKind, out var definition)); | ||||
|         Assert.NotNull(definition); | ||||
|         Assert.Equal(PluginJob.JobKind, definition.Kind); | ||||
|         Assert.Equal("StellaOps.Feedser.Core.Tests.PluginJob", definition.JobType.FullName); | ||||
|         Assert.Equal("StellaOps.Concelier.Core.Tests.PluginJob", definition.JobType.FullName); | ||||
|         Assert.Equal(TimeSpan.FromSeconds(45), definition.Timeout); | ||||
|         Assert.Equal(TimeSpan.FromSeconds(5), definition.LeaseDuration); | ||||
|         Assert.Equal("*/10 * * * *", definition.CronExpression); | ||||
| @@ -1,9 +1,9 @@ | ||||
| using System; | ||||
| using Microsoft.Extensions.DependencyInjection; | ||||
| using Microsoft.Extensions.Options; | ||||
| using StellaOps.Feedser.Core.Jobs; | ||||
| using StellaOps.Concelier.Core.Jobs; | ||||
| 
 | ||||
| namespace StellaOps.Feedser.Core.Tests; | ||||
| namespace StellaOps.Concelier.Core.Tests; | ||||
| 
 | ||||
| public sealed class JobSchedulerBuilderTests | ||||
| { | ||||
| @@ -4,9 +4,9 @@ using System.Threading.Tasks; | ||||
| using Microsoft.Extensions.Configuration; | ||||
| using Microsoft.Extensions.DependencyInjection; | ||||
| using StellaOps.DependencyInjection; | ||||
| using StellaOps.Feedser.Core.Jobs; | ||||
| using StellaOps.Concelier.Core.Jobs; | ||||
| 
 | ||||
| namespace StellaOps.Feedser.Core.Tests; | ||||
| namespace StellaOps.Concelier.Core.Tests; | ||||
| 
 | ||||
| public sealed class TestPluginRoutine : IDependencyInjectionRoutine | ||||
| { | ||||
| @@ -5,6 +5,6 @@ | ||||
|     <Nullable>enable</Nullable> | ||||
|   </PropertyGroup> | ||||
|   <ItemGroup> | ||||
|     <ProjectReference Include="../StellaOps.Feedser.Core/StellaOps.Feedser.Core.csproj" /> | ||||
|     <ProjectReference Include="../StellaOps.Concelier.Core/StellaOps.Concelier.Core.csproj" /> | ||||
|   </ItemGroup> | ||||
| </Project> | ||||
| @@ -26,7 +26,7 @@ Out: business logic of connectors/exporters, HTTP handlers (owned by WebService) | ||||
| - Logs: kind, trigger, params hash, lease holder, outcome; redact params containing secrets. | ||||
| - Honor CancellationToken early and often. | ||||
| ## Tests | ||||
| - Author and review coverage in `../StellaOps.Feedser.Core.Tests`. | ||||
| - Shared fixtures (e.g., `MongoIntegrationFixture`, `ConnectorTestHarness`) live in `../StellaOps.Feedser.Testing`. | ||||
| - Author and review coverage in `../StellaOps.Concelier.Core.Tests`. | ||||
| - Shared fixtures (e.g., `MongoIntegrationFixture`, `ConnectorTestHarness`) live in `../StellaOps.Concelier.Testing`. | ||||
| - Keep fixtures deterministic; match new cases to real-world advisories or regression scenarios. | ||||
| 
 | ||||
| @@ -1,7 +1,7 @@ | ||||
| using System.Collections.Immutable; | ||||
| using StellaOps.Feedser.Models; | ||||
| using StellaOps.Concelier.Models; | ||||
| 
 | ||||
| namespace StellaOps.Feedser.Core; | ||||
| namespace StellaOps.Concelier.Core; | ||||
| 
 | ||||
| /// <summary> | ||||
| /// Result emitted by <see cref="CanonicalMerger"/> describing the merged advisory and analytics about key decisions. | ||||
| @@ -1,9 +1,9 @@ | ||||
| using System.Collections.Immutable; | ||||
| using System.Security.Cryptography; | ||||
| using System.Text; | ||||
| using StellaOps.Feedser.Models; | ||||
| using StellaOps.Concelier.Models; | ||||
| 
 | ||||
| namespace StellaOps.Feedser.Core; | ||||
| namespace StellaOps.Concelier.Core; | ||||
| 
 | ||||
| /// <summary> | ||||
| /// Resolves conflicts between GHSA, NVD, and OSV advisories into a single canonical advisory following | ||||
| @@ -1,4 +1,4 @@ | ||||
| namespace StellaOps.Feedser.Core.Jobs; | ||||
| namespace StellaOps.Concelier.Core.Jobs; | ||||
| 
 | ||||
| public interface IJob | ||||
| { | ||||
| @@ -1,4 +1,4 @@ | ||||
| namespace StellaOps.Feedser.Core.Jobs; | ||||
| namespace StellaOps.Concelier.Core.Jobs; | ||||
| 
 | ||||
| public interface IJobCoordinator | ||||
| { | ||||
| @@ -1,4 +1,4 @@ | ||||
| namespace StellaOps.Feedser.Core.Jobs; | ||||
| namespace StellaOps.Concelier.Core.Jobs; | ||||
| 
 | ||||
| public interface IJobStore | ||||
| { | ||||
| @@ -1,4 +1,4 @@ | ||||
| namespace StellaOps.Feedser.Core.Jobs; | ||||
| namespace StellaOps.Concelier.Core.Jobs; | ||||
| 
 | ||||
| public interface ILeaseStore | ||||
| { | ||||
| @@ -8,7 +8,7 @@ using Microsoft.Extensions.DependencyInjection; | ||||
| using Microsoft.Extensions.Logging; | ||||
| using Microsoft.Extensions.Options; | ||||
| 
 | ||||
| namespace StellaOps.Feedser.Core.Jobs; | ||||
| namespace StellaOps.Concelier.Core.Jobs; | ||||
| 
 | ||||
| public sealed class JobCoordinator : IJobCoordinator | ||||
| { | ||||
| @@ -1,4 +1,4 @@ | ||||
| namespace StellaOps.Feedser.Core.Jobs; | ||||
| namespace StellaOps.Concelier.Core.Jobs; | ||||
| 
 | ||||
| public sealed record JobDefinition( | ||||
|     string Kind, | ||||
| @@ -1,15 +1,15 @@ | ||||
| using System.Diagnostics; | ||||
| using System.Diagnostics.Metrics; | ||||
| 
 | ||||
| namespace StellaOps.Feedser.Core.Jobs; | ||||
| namespace StellaOps.Concelier.Core.Jobs; | ||||
| 
 | ||||
| public sealed class JobDiagnostics : IDisposable | ||||
| { | ||||
|     public const string ActivitySourceName = "StellaOps.Feedser.Jobs"; | ||||
|     public const string MeterName = "StellaOps.Feedser.Jobs"; | ||||
|     public const string TriggerActivityName = "feedser.job.trigger"; | ||||
|     public const string ExecuteActivityName = "feedser.job.execute"; | ||||
|     public const string SchedulerActivityName = "feedser.scheduler.evaluate"; | ||||
|     public const string ActivitySourceName = "StellaOps.Concelier.Jobs"; | ||||
|     public const string MeterName = "StellaOps.Concelier.Jobs"; | ||||
|     public const string TriggerActivityName = "concelier.job.trigger"; | ||||
|     public const string ExecuteActivityName = "concelier.job.execute"; | ||||
|     public const string SchedulerActivityName = "concelier.scheduler.evaluate"; | ||||
| 
 | ||||
|     private readonly Counter<long> _triggersAccepted; | ||||
|     private readonly Counter<long> _triggersRejected; | ||||
| @@ -24,32 +24,32 @@ public sealed class JobDiagnostics : IDisposable | ||||
|         Meter = new Meter(MeterName); | ||||
| 
 | ||||
|         _triggersAccepted = Meter.CreateCounter<long>( | ||||
|             name: "feedser.jobs.triggers.accepted", | ||||
|             name: "concelier.jobs.triggers.accepted", | ||||
|             unit: "count", | ||||
|             description: "Number of job trigger requests accepted for execution."); | ||||
| 
 | ||||
|         _triggersRejected = Meter.CreateCounter<long>( | ||||
|             name: "feedser.jobs.triggers.rejected", | ||||
|             name: "concelier.jobs.triggers.rejected", | ||||
|             unit: "count", | ||||
|             description: "Number of job trigger requests rejected or ignored by the coordinator."); | ||||
| 
 | ||||
|         _runsCompleted = Meter.CreateCounter<long>( | ||||
|             name: "feedser.jobs.runs.completed", | ||||
|             name: "concelier.jobs.runs.completed", | ||||
|             unit: "count", | ||||
|             description: "Number of job executions that have finished grouped by outcome."); | ||||
| 
 | ||||
|         _runsActive = Meter.CreateUpDownCounter<long>( | ||||
|             name: "feedser.jobs.runs.active", | ||||
|             name: "concelier.jobs.runs.active", | ||||
|             unit: "count", | ||||
|             description: "Current number of running job executions."); | ||||
| 
 | ||||
|         _runDurationSeconds = Meter.CreateHistogram<double>( | ||||
|             name: "feedser.jobs.runs.duration", | ||||
|             name: "concelier.jobs.runs.duration", | ||||
|             unit: "s", | ||||
|             description: "Distribution of job execution durations in seconds."); | ||||
| 
 | ||||
|         _schedulerSkewMilliseconds = Meter.CreateHistogram<double>( | ||||
|             name: "feedser.scheduler.skew", | ||||
|             name: "concelier.scheduler.skew", | ||||
|             unit: "ms", | ||||
|             description: "Difference between the intended and actual scheduler fire time in milliseconds."); | ||||
|     } | ||||
| @@ -1,7 +1,7 @@ | ||||
| using Microsoft.Extensions.DependencyInjection; | ||||
| using Microsoft.Extensions.Logging; | ||||
| 
 | ||||
| namespace StellaOps.Feedser.Core.Jobs; | ||||
| namespace StellaOps.Concelier.Core.Jobs; | ||||
| 
 | ||||
| public sealed class JobExecutionContext | ||||
| { | ||||
| @@ -1,4 +1,4 @@ | ||||
| namespace StellaOps.Feedser.Core.Jobs; | ||||
| namespace StellaOps.Concelier.Core.Jobs; | ||||
| 
 | ||||
| public sealed record JobLease( | ||||
|     string Key, | ||||
| @@ -8,7 +8,7 @@ using Microsoft.Extensions.Logging; | ||||
| using StellaOps.DependencyInjection; | ||||
| using StellaOps.Plugin.Hosting; | ||||
| 
 | ||||
| namespace StellaOps.Feedser.Core.Jobs; | ||||
| namespace StellaOps.Concelier.Core.Jobs; | ||||
| 
 | ||||
| public static class JobPluginRegistrationExtensions | ||||
| { | ||||
| @@ -1,4 +1,4 @@ | ||||
| namespace StellaOps.Feedser.Core.Jobs; | ||||
| namespace StellaOps.Concelier.Core.Jobs; | ||||
| 
 | ||||
| public sealed record JobRunCompletion( | ||||
|     JobRunStatus Status, | ||||
| @@ -1,4 +1,4 @@ | ||||
| namespace StellaOps.Feedser.Core.Jobs; | ||||
| namespace StellaOps.Concelier.Core.Jobs; | ||||
| 
 | ||||
| public sealed record JobRunCreateRequest( | ||||
|     string Kind, | ||||
| @@ -1,4 +1,4 @@ | ||||
| namespace StellaOps.Feedser.Core.Jobs; | ||||
| namespace StellaOps.Concelier.Core.Jobs; | ||||
| 
 | ||||
| /// <summary> | ||||
| /// Immutable projection of a job run as stored in persistence. | ||||
| @@ -1,4 +1,4 @@ | ||||
| namespace StellaOps.Feedser.Core.Jobs; | ||||
| namespace StellaOps.Concelier.Core.Jobs; | ||||
| 
 | ||||
| public enum JobRunStatus | ||||
| { | ||||
| @@ -1,7 +1,7 @@ | ||||
| using System; | ||||
| using Microsoft.Extensions.DependencyInjection; | ||||
| 
 | ||||
| namespace StellaOps.Feedser.Core.Jobs; | ||||
| namespace StellaOps.Concelier.Core.Jobs; | ||||
| 
 | ||||
| public sealed class JobSchedulerBuilder | ||||
| { | ||||
| @@ -4,7 +4,7 @@ using Microsoft.Extensions.Hosting; | ||||
| using Microsoft.Extensions.Logging; | ||||
| using Microsoft.Extensions.Options; | ||||
| 
 | ||||
| namespace StellaOps.Feedser.Core.Jobs; | ||||
| namespace StellaOps.Concelier.Core.Jobs; | ||||
| 
 | ||||
| /// <summary> | ||||
| /// Background service that evaluates cron expressions for registered jobs and triggers them. | ||||
| @@ -1,4 +1,4 @@ | ||||
| namespace StellaOps.Feedser.Core.Jobs; | ||||
| namespace StellaOps.Concelier.Core.Jobs; | ||||
| 
 | ||||
| public sealed class JobSchedulerOptions | ||||
| { | ||||
| @@ -1,4 +1,4 @@ | ||||
| namespace StellaOps.Feedser.Core.Jobs; | ||||
| namespace StellaOps.Concelier.Core.Jobs; | ||||
| 
 | ||||
| public enum JobTriggerOutcome | ||||
| { | ||||
| @@ -2,7 +2,7 @@ using Microsoft.Extensions.DependencyInjection; | ||||
| using Microsoft.Extensions.DependencyInjection.Extensions; | ||||
| using Microsoft.Extensions.Options; | ||||
| 
 | ||||
| namespace StellaOps.Feedser.Core.Jobs; | ||||
| namespace StellaOps.Concelier.Core.Jobs; | ||||
| 
 | ||||
| public static class JobServiceCollectionExtensions | ||||
| { | ||||
| @@ -13,7 +13,7 @@ | ||||
|     <PackageReference Include="Cronos" Version="0.10.0" /> | ||||
|   </ItemGroup> | ||||
|   <ItemGroup> | ||||
|     <ProjectReference Include="..\StellaOps.Feedser.Models\StellaOps.Feedser.Models.csproj" /> | ||||
|     <ProjectReference Include="..\StellaOps.Concelier.Models\StellaOps.Concelier.Models.csproj" /> | ||||
|     <ProjectReference Include="..\StellaOps.Plugin\StellaOps.Plugin.csproj" /> | ||||
|   </ItemGroup> | ||||
| </Project> | ||||
| @@ -7,10 +7,10 @@ using System.Security.Cryptography; | ||||
| using System.Runtime.CompilerServices; | ||||
| using System.Threading; | ||||
| using System.Threading.Tasks; | ||||
| using StellaOps.Feedser.Exporter.Json; | ||||
| using StellaOps.Feedser.Models; | ||||
| using StellaOps.Concelier.Exporter.Json; | ||||
| using StellaOps.Concelier.Models; | ||||
| 
 | ||||
| namespace StellaOps.Feedser.Exporter.Json.Tests; | ||||
| namespace StellaOps.Concelier.Exporter.Json.Tests; | ||||
| 
 | ||||
| public sealed class JsonExportSnapshotBuilderTests : IDisposable | ||||
| { | ||||
| @@ -18,7 +18,7 @@ public sealed class JsonExportSnapshotBuilderTests : IDisposable | ||||
| 
 | ||||
|     public JsonExportSnapshotBuilderTests() | ||||
|     { | ||||
|         _root = Directory.CreateTempSubdirectory("feedser-json-export-tests").FullName; | ||||
|         _root = Directory.CreateTempSubdirectory("concelier-json-export-tests").FullName; | ||||
|     } | ||||
| 
 | ||||
|     [Fact] | ||||
| @@ -141,7 +141,7 @@ public sealed class JsonExportSnapshotBuilderTests : IDisposable | ||||
|             cvssMetrics: Array.Empty<CvssMetric>(), | ||||
|             provenance: new[] | ||||
|             { | ||||
|                 new AdvisoryProvenance("feedser", "normalized", "canonical", DateTimeOffset.Parse("2024-01-02T00:00:00Z", CultureInfo.InvariantCulture)), | ||||
|                 new AdvisoryProvenance("concelier", "normalized", "canonical", DateTimeOffset.Parse("2024-01-02T00:00:00Z", CultureInfo.InvariantCulture)), | ||||
|             }); | ||||
|     } | ||||
| 
 | ||||
| @@ -5,13 +5,13 @@ using Microsoft.Extensions.Configuration; | ||||
| using Microsoft.Extensions.DependencyInjection; | ||||
| using Microsoft.Extensions.Logging; | ||||
| using Microsoft.Extensions.Options; | ||||
| using StellaOps.Feedser.Core.Jobs; | ||||
| using StellaOps.Feedser.Exporter.Json; | ||||
| using StellaOps.Feedser.Storage.Mongo.Advisories; | ||||
| using StellaOps.Feedser.Storage.Mongo.Exporting; | ||||
| using StellaOps.Feedser.Models; | ||||
| using StellaOps.Concelier.Core.Jobs; | ||||
| using StellaOps.Concelier.Exporter.Json; | ||||
| using StellaOps.Concelier.Storage.Mongo.Advisories; | ||||
| using StellaOps.Concelier.Storage.Mongo.Exporting; | ||||
| using StellaOps.Concelier.Models; | ||||
| 
 | ||||
| namespace StellaOps.Feedser.Exporter.Json.Tests; | ||||
| namespace StellaOps.Concelier.Exporter.Json.Tests; | ||||
| 
 | ||||
| public sealed class JsonExporterDependencyInjectionRoutineTests | ||||
| { | ||||
| @@ -5,10 +5,10 @@ using System.IO; | ||||
| using System.Linq; | ||||
| using System.Threading; | ||||
| using System.Threading.Tasks; | ||||
| using StellaOps.Feedser.Exporter.Json; | ||||
| using StellaOps.Feedser.Models; | ||||
| using StellaOps.Concelier.Exporter.Json; | ||||
| using StellaOps.Concelier.Models; | ||||
| 
 | ||||
| namespace StellaOps.Feedser.Exporter.Json.Tests; | ||||
| namespace StellaOps.Concelier.Exporter.Json.Tests; | ||||
| 
 | ||||
| public sealed class JsonExporterParitySmokeTests : IDisposable | ||||
| { | ||||
| @@ -16,7 +16,7 @@ public sealed class JsonExporterParitySmokeTests : IDisposable | ||||
| 
 | ||||
|     public JsonExporterParitySmokeTests() | ||||
|     { | ||||
|         _root = Directory.CreateTempSubdirectory("feedser-json-parity-tests").FullName; | ||||
|         _root = Directory.CreateTempSubdirectory("concelier-json-parity-tests").FullName; | ||||
|     } | ||||
| 
 | ||||
|     [Fact] | ||||
| @@ -10,12 +10,12 @@ using System.Threading.Tasks; | ||||
| using Microsoft.Extensions.DependencyInjection; | ||||
| using Microsoft.Extensions.Logging.Abstractions; | ||||
| using Microsoft.Extensions.Options; | ||||
| using StellaOps.Feedser.Exporter.Json; | ||||
| using StellaOps.Feedser.Models; | ||||
| using StellaOps.Feedser.Storage.Mongo.Advisories; | ||||
| using StellaOps.Feedser.Storage.Mongo.Exporting; | ||||
| using StellaOps.Concelier.Exporter.Json; | ||||
| using StellaOps.Concelier.Models; | ||||
| using StellaOps.Concelier.Storage.Mongo.Advisories; | ||||
| using StellaOps.Concelier.Storage.Mongo.Exporting; | ||||
| 
 | ||||
| namespace StellaOps.Feedser.Exporter.Json.Tests; | ||||
| namespace StellaOps.Concelier.Exporter.Json.Tests; | ||||
| 
 | ||||
| public sealed class JsonFeedExporterTests : IDisposable | ||||
| { | ||||
| @@ -23,7 +23,7 @@ public sealed class JsonFeedExporterTests : IDisposable | ||||
| 
 | ||||
|     public JsonFeedExporterTests() | ||||
|     { | ||||
|         _root = Directory.CreateTempSubdirectory("feedser-json-exporter-tests").FullName; | ||||
|         _root = Directory.CreateTempSubdirectory("concelier-json-exporter-tests").FullName; | ||||
|     } | ||||
| 
 | ||||
|     [Fact] | ||||
| @@ -0,0 +1,13 @@ | ||||
| <Project Sdk="Microsoft.NET.Sdk"> | ||||
|   <PropertyGroup> | ||||
|     <TargetFramework>net10.0</TargetFramework> | ||||
|     <ImplicitUsings>enable</ImplicitUsings> | ||||
|     <Nullable>enable</Nullable> | ||||
|   </PropertyGroup> | ||||
|   <ItemGroup> | ||||
|     <ProjectReference Include="../StellaOps.Concelier.Core/StellaOps.Concelier.Core.csproj" /> | ||||
|     <ProjectReference Include="../StellaOps.Concelier.Exporter.Json/StellaOps.Concelier.Exporter.Json.csproj" /> | ||||
|     <ProjectReference Include="../StellaOps.Concelier.Models/StellaOps.Concelier.Models.csproj" /> | ||||
|     <ProjectReference Include="../StellaOps.Concelier.Storage.Mongo/StellaOps.Concelier.Storage.Mongo.csproj" /> | ||||
|   </ItemGroup> | ||||
| </Project> | ||||
| @@ -1,10 +1,10 @@ | ||||
| using System.Collections.Generic; | ||||
| using System.Globalization; | ||||
| using System.IO; | ||||
| using StellaOps.Feedser.Exporter.Json; | ||||
| using StellaOps.Feedser.Models; | ||||
| using StellaOps.Concelier.Exporter.Json; | ||||
| using StellaOps.Concelier.Models; | ||||
| 
 | ||||
| namespace StellaOps.Feedser.Exporter.Json.Tests; | ||||
| namespace StellaOps.Concelier.Exporter.Json.Tests; | ||||
| 
 | ||||
| public sealed class VulnListJsonExportPathResolverTests | ||||
| { | ||||
| @@ -22,7 +22,7 @@ Out: ORAS push and Trivy DB BoltDB writing (owned by Trivy exporter). | ||||
| - Metrics: export.json.records, bytes, duration, delta.changed. | ||||
| - Logs: target path, record counts, digest; no sensitive data. | ||||
| ## Tests | ||||
| - Author and review coverage in `../StellaOps.Feedser.Exporter.Json.Tests`. | ||||
| - Shared fixtures (e.g., `MongoIntegrationFixture`, `ConnectorTestHarness`) live in `../StellaOps.Feedser.Testing`. | ||||
| - Author and review coverage in `../StellaOps.Concelier.Exporter.Json.Tests`. | ||||
| - Shared fixtures (e.g., `MongoIntegrationFixture`, `ConnectorTestHarness`) live in `../StellaOps.Concelier.Testing`. | ||||
| - Keep fixtures deterministic; match new cases to real-world advisories or regression scenarios. | ||||
| 
 | ||||
| @@ -5,7 +5,7 @@ using System.Linq; | ||||
| using System.Security.Cryptography; | ||||
| using System.Text; | ||||
| 
 | ||||
| namespace StellaOps.Feedser.Exporter.Json; | ||||
| namespace StellaOps.Concelier.Exporter.Json; | ||||
| 
 | ||||
| public static class ExportDigestCalculator | ||||
| { | ||||
| @@ -1,7 +1,7 @@ | ||||
| using System; | ||||
| using System.Reflection; | ||||
| 
 | ||||
| namespace StellaOps.Feedser.Exporter.Json; | ||||
| namespace StellaOps.Concelier.Exporter.Json; | ||||
| 
 | ||||
| public static class ExporterVersion | ||||
| { | ||||
| @@ -1,6 +1,6 @@ | ||||
| using StellaOps.Feedser.Models; | ||||
| using StellaOps.Concelier.Models; | ||||
| 
 | ||||
| namespace StellaOps.Feedser.Exporter.Json; | ||||
| namespace StellaOps.Concelier.Exporter.Json; | ||||
| 
 | ||||
| public interface IJsonExportPathResolver | ||||
| { | ||||
| @@ -1,6 +1,6 @@ | ||||
| using System; | ||||
| 
 | ||||
| namespace StellaOps.Feedser.Exporter.Json; | ||||
| namespace StellaOps.Concelier.Exporter.Json; | ||||
| 
 | ||||
| /// <summary> | ||||
| /// Metadata describing a single file produced by the JSON exporter. | ||||
| @@ -2,9 +2,9 @@ using System; | ||||
| using System.Threading; | ||||
| using System.Threading.Tasks; | ||||
| using Microsoft.Extensions.Logging; | ||||
| using StellaOps.Feedser.Core.Jobs; | ||||
| using StellaOps.Concelier.Core.Jobs; | ||||
| 
 | ||||
| namespace StellaOps.Feedser.Exporter.Json; | ||||
| namespace StellaOps.Concelier.Exporter.Json; | ||||
| 
 | ||||
| public sealed class JsonExportJob : IJob | ||||
| { | ||||
| @@ -7,7 +7,7 @@ using System.Text.Json.Serialization; | ||||
| using System.Threading; | ||||
| using System.Threading.Tasks; | ||||
| 
 | ||||
| namespace StellaOps.Feedser.Exporter.Json; | ||||
| namespace StellaOps.Concelier.Exporter.Json; | ||||
| 
 | ||||
| internal static class JsonExportManifestWriter | ||||
| { | ||||
| @@ -1,6 +1,6 @@ | ||||
| using System.IO; | ||||
| 
 | ||||
| namespace StellaOps.Feedser.Exporter.Json; | ||||
| namespace StellaOps.Concelier.Exporter.Json; | ||||
| 
 | ||||
| /// <summary> | ||||
| /// Configuration for JSON exporter output paths and determinism controls. | ||||
| @@ -3,7 +3,7 @@ using System.Collections.Generic; | ||||
| using System.Collections.Immutable; | ||||
| using System.Linq; | ||||
| 
 | ||||
| namespace StellaOps.Feedser.Exporter.Json; | ||||
| namespace StellaOps.Concelier.Exporter.Json; | ||||
| 
 | ||||
| public sealed class JsonExportResult | ||||
| { | ||||
| @@ -5,9 +5,9 @@ using System.Runtime.CompilerServices; | ||||
| using System.Security.Cryptography; | ||||
| using System.Text; | ||||
| using System.Threading.Tasks; | ||||
| using StellaOps.Feedser.Models; | ||||
| using StellaOps.Concelier.Models; | ||||
| 
 | ||||
| namespace StellaOps.Feedser.Exporter.Json; | ||||
| namespace StellaOps.Concelier.Exporter.Json; | ||||
| 
 | ||||
| /// <summary> | ||||
| /// Writes canonical advisory snapshots into a vuln-list style directory tree with deterministic ordering. | ||||
| @@ -5,14 +5,14 @@ using Microsoft.Extensions.DependencyInjection; | ||||
| using Microsoft.Extensions.DependencyInjection.Extensions; | ||||
| using Microsoft.Extensions.Options; | ||||
| using StellaOps.DependencyInjection; | ||||
| using StellaOps.Feedser.Core.Jobs; | ||||
| using StellaOps.Feedser.Storage.Mongo.Exporting; | ||||
| using StellaOps.Concelier.Core.Jobs; | ||||
| using StellaOps.Concelier.Storage.Mongo.Exporting; | ||||
| 
 | ||||
| namespace StellaOps.Feedser.Exporter.Json; | ||||
| namespace StellaOps.Concelier.Exporter.Json; | ||||
| 
 | ||||
| public sealed class JsonExporterDependencyInjectionRoutine : IDependencyInjectionRoutine | ||||
| { | ||||
|     private const string ConfigurationSection = "feedser:exporters:json"; | ||||
|     private const string ConfigurationSection = "concelier:exporters:json"; | ||||
| 
 | ||||
|     public IServiceCollection Register(IServiceCollection services, IConfiguration configuration) | ||||
|     { | ||||
| @@ -1,9 +1,9 @@ | ||||
| using System; | ||||
| using Microsoft.Extensions.DependencyInjection; | ||||
| using StellaOps.Feedser.Storage.Mongo.Advisories; | ||||
| using StellaOps.Concelier.Storage.Mongo.Advisories; | ||||
| using StellaOps.Plugin; | ||||
| 
 | ||||
| namespace StellaOps.Feedser.Exporter.Json; | ||||
| namespace StellaOps.Concelier.Exporter.Json; | ||||
| 
 | ||||
| public sealed class JsonExporterPlugin : IExporterPlugin | ||||
| { | ||||
| @@ -4,11 +4,11 @@ using System.IO; | ||||
| using System.Linq; | ||||
| using Microsoft.Extensions.Logging; | ||||
| using Microsoft.Extensions.Options; | ||||
| using StellaOps.Feedser.Storage.Mongo.Advisories; | ||||
| using StellaOps.Feedser.Storage.Mongo.Exporting; | ||||
| using StellaOps.Concelier.Storage.Mongo.Advisories; | ||||
| using StellaOps.Concelier.Storage.Mongo.Exporting; | ||||
| using StellaOps.Plugin; | ||||
| 
 | ||||
| namespace StellaOps.Feedser.Exporter.Json; | ||||
| namespace StellaOps.Concelier.Exporter.Json; | ||||
| 
 | ||||
| public sealed class JsonFeedExporter : IFeedExporter | ||||
| { | ||||
| @@ -8,9 +8,9 @@ | ||||
|     <TreatWarningsAsErrors>true</TreatWarningsAsErrors> | ||||
|   </PropertyGroup> | ||||
|   <ItemGroup> | ||||
|     <ProjectReference Include="..\StellaOps.Feedser.Models\StellaOps.Feedser.Models.csproj" /> | ||||
|     <ProjectReference Include="..\StellaOps.Feedser.Normalization\StellaOps.Feedser.Normalization.csproj" /> | ||||
|     <ProjectReference Include="..\StellaOps.Feedser.Storage.Mongo\StellaOps.Feedser.Storage.Mongo.csproj" /> | ||||
|     <ProjectReference Include="..\StellaOps.Concelier.Models\StellaOps.Concelier.Models.csproj" /> | ||||
|     <ProjectReference Include="..\StellaOps.Concelier.Normalization\StellaOps.Concelier.Normalization.csproj" /> | ||||
|     <ProjectReference Include="..\StellaOps.Concelier.Storage.Mongo\StellaOps.Concelier.Storage.Mongo.csproj" /> | ||||
|     <ProjectReference Include="../StellaOps.Plugin/StellaOps.Plugin.csproj" /> | ||||
|     <ProjectReference Include="../StellaOps.DependencyInjection/StellaOps.DependencyInjection.csproj" /> | ||||
|   </ItemGroup> | ||||
| @@ -9,4 +9,4 @@ | ||||
| |Parity smoke vs upstream vuln-list|QA|Exporters|DONE – `JsonExporterParitySmokeTests` covers common ecosystems against vuln-list layout.| | ||||
| |Stream advisories during export|BE-Export|Storage.Mongo|DONE – exporter + streaming-only test ensures single enumeration and per-file digest capture.| | ||||
| |Emit export manifest with digest metadata|BE-Export|Exporters|DONE – manifest now includes per-file digests/sizes alongside tree digest.| | ||||
| |Surface new advisory fields (description/CWEs/canonical metric)|BE-Export|Models, Core|DONE (2025-10-15) – JSON exporter validated with new fixtures ensuring description/CWEs/canonical metric are preserved in outputs; `dotnet test src/StellaOps.Feedser.Exporter.Json.Tests` run 2025-10-15 for regression coverage.| | ||||
| |Surface new advisory fields (description/CWEs/canonical metric)|BE-Export|Models, Core|DONE (2025-10-15) – JSON exporter validated with new fixtures ensuring description/CWEs/canonical metric are preserved in outputs; `dotnet test src/StellaOps.Concelier.Exporter.Json.Tests` run 2025-10-15 for regression coverage.| | ||||
| @@ -3,10 +3,10 @@ using System.Collections.Generic; | ||||
| using System.IO; | ||||
| using System.Linq; | ||||
| using System.Text.RegularExpressions; | ||||
| using StellaOps.Feedser.Models; | ||||
| using StellaOps.Feedser.Normalization.Identifiers; | ||||
| using StellaOps.Concelier.Models; | ||||
| using StellaOps.Concelier.Normalization.Identifiers; | ||||
| 
 | ||||
| namespace StellaOps.Feedser.Exporter.Json; | ||||
| namespace StellaOps.Concelier.Exporter.Json; | ||||
| 
 | ||||
| /// <summary> | ||||
| /// Path resolver approximating the directory layout used by aquasecurity/vuln-list. | ||||
| @@ -0,0 +1,13 @@ | ||||
| <Project Sdk="Microsoft.NET.Sdk"> | ||||
|   <PropertyGroup> | ||||
|     <TargetFramework>net10.0</TargetFramework> | ||||
|     <ImplicitUsings>enable</ImplicitUsings> | ||||
|     <Nullable>enable</Nullable> | ||||
|   </PropertyGroup> | ||||
|   <ItemGroup> | ||||
|     <ProjectReference Include="../StellaOps.Concelier.Exporter.Json/StellaOps.Concelier.Exporter.Json.csproj" /> | ||||
|     <ProjectReference Include="../StellaOps.Concelier.Exporter.TrivyDb/StellaOps.Concelier.Exporter.TrivyDb.csproj" /> | ||||
|     <ProjectReference Include="../StellaOps.Concelier.Models/StellaOps.Concelier.Models.csproj" /> | ||||
|     <ProjectReference Include="../StellaOps.Concelier.Storage.Mongo/StellaOps.Concelier.Storage.Mongo.csproj" /> | ||||
|   </ItemGroup> | ||||
| </Project> | ||||
| @@ -1,8 +1,8 @@ | ||||
| using System; | ||||
| using StellaOps.Feedser.Exporter.TrivyDb; | ||||
| using StellaOps.Feedser.Storage.Mongo.Exporting; | ||||
| using StellaOps.Concelier.Exporter.TrivyDb; | ||||
| using StellaOps.Concelier.Storage.Mongo.Exporting; | ||||
| 
 | ||||
| namespace StellaOps.Feedser.Exporter.TrivyDb.Tests; | ||||
| namespace StellaOps.Concelier.Exporter.TrivyDb.Tests; | ||||
| 
 | ||||
| public sealed class TrivyDbExportPlannerTests | ||||
| { | ||||
| @@ -33,7 +33,7 @@ public sealed class TrivyDbExportPlannerTests | ||||
|             LastFullDigest: "sha256:base", | ||||
|             LastDeltaDigest: null, | ||||
|             ExportCursor: "sha256:unchanged", | ||||
|             TargetRepository: "feedser/trivy", | ||||
|             TargetRepository: "concelier/trivy", | ||||
|             ExporterVersion: "1.0", | ||||
|             UpdatedAt: DateTimeOffset.UtcNow, | ||||
|             Files: existingManifest); | ||||
| @@ -61,7 +61,7 @@ public sealed class TrivyDbExportPlannerTests | ||||
|             LastFullDigest: "sha256:base", | ||||
|             LastDeltaDigest: null, | ||||
|             ExportCursor: "sha256:old", | ||||
|             TargetRepository: "feedser/trivy", | ||||
|             TargetRepository: "concelier/trivy", | ||||
|             ExporterVersion: "1.0", | ||||
|             UpdatedAt: DateTimeOffset.UtcNow, | ||||
|             Files: manifest); | ||||
| @@ -11,13 +11,13 @@ using System.Threading.Tasks; | ||||
| using Microsoft.Extensions.DependencyInjection; | ||||
| using Microsoft.Extensions.Logging.Abstractions; | ||||
| using Microsoft.Extensions.Options; | ||||
| using StellaOps.Feedser.Exporter.Json; | ||||
| using StellaOps.Feedser.Exporter.TrivyDb; | ||||
| using StellaOps.Feedser.Models; | ||||
| using StellaOps.Feedser.Storage.Mongo.Advisories; | ||||
| using StellaOps.Feedser.Storage.Mongo.Exporting; | ||||
| using StellaOps.Concelier.Exporter.Json; | ||||
| using StellaOps.Concelier.Exporter.TrivyDb; | ||||
| using StellaOps.Concelier.Models; | ||||
| using StellaOps.Concelier.Storage.Mongo.Advisories; | ||||
| using StellaOps.Concelier.Storage.Mongo.Exporting; | ||||
| 
 | ||||
| namespace StellaOps.Feedser.Exporter.TrivyDb.Tests; | ||||
| namespace StellaOps.Concelier.Exporter.TrivyDb.Tests; | ||||
| 
 | ||||
| public sealed class TrivyDbFeedExporterTests : IDisposable | ||||
| { | ||||
| @@ -26,7 +26,7 @@ public sealed class TrivyDbFeedExporterTests : IDisposable | ||||
| 
 | ||||
|     public TrivyDbFeedExporterTests() | ||||
|     { | ||||
|         _root = Directory.CreateTempSubdirectory("feedser-trivy-exporter-tests").FullName; | ||||
|         _root = Directory.CreateTempSubdirectory("concelier-trivy-exporter-tests").FullName; | ||||
|         _jsonRoot = Path.Combine(_root, "tree"); | ||||
|     } | ||||
| 
 | ||||
| @@ -7,10 +7,10 @@ using System.Text; | ||||
| using System.Text.Json; | ||||
| using System.Threading; | ||||
| using System.Threading.Tasks; | ||||
| using StellaOps.Feedser.Storage.Mongo.Exporting; | ||||
| using StellaOps.Concelier.Storage.Mongo.Exporting; | ||||
| using Xunit; | ||||
| 
 | ||||
| namespace StellaOps.Feedser.Exporter.TrivyDb.Tests; | ||||
| namespace StellaOps.Concelier.Exporter.TrivyDb.Tests; | ||||
| 
 | ||||
| public sealed class TrivyDbOciWriterTests : IDisposable | ||||
| { | ||||
| @@ -4,9 +4,9 @@ using System.Linq; | ||||
| using System.Security.Cryptography; | ||||
| using System.Text; | ||||
| using System.Text.Json; | ||||
| using StellaOps.Feedser.Exporter.TrivyDb; | ||||
| using StellaOps.Concelier.Exporter.TrivyDb; | ||||
| 
 | ||||
| namespace StellaOps.Feedser.Exporter.TrivyDb.Tests; | ||||
| namespace StellaOps.Concelier.Exporter.TrivyDb.Tests; | ||||
| 
 | ||||
| public sealed class TrivyDbPackageBuilderTests | ||||
| { | ||||
| @@ -14,7 +14,7 @@ Exporter producing a Trivy-compatible database artifact for self-hosting or offl | ||||
| - JSON exporter (optional precursor) if choosing the builder path. | ||||
| ## Interfaces & contracts | ||||
| - IFeedExporter.Name = "trivy-db"; ExportAsync(IServiceProvider, CancellationToken). | ||||
| - FeedserOptions.packaging.trivy governs repo/tag/publish/offline_bundle. | ||||
| - ConcelierOptions.packaging.trivy governs repo/tag/publish/offline_bundle. | ||||
| - Deterministic sorting and timestamp discipline (UTC; consider build reproducibility knobs). | ||||
| ## In/Out of scope | ||||
| In: assembling builder inputs, packing tar.gz, pushing to registry when configured. | ||||
| @@ -23,7 +23,7 @@ Out: signing (external pipeline), scanner behavior. | ||||
| - Metrics: export.trivy.records, size_bytes, duration, oras.push.success/fail. | ||||
| - Logs: export path, repo/tag, digest; redact credentials; backoff on push errors. | ||||
| ## Tests | ||||
| - Author and review coverage in `../StellaOps.Feedser.Exporter.TrivyDb.Tests`. | ||||
| - Shared fixtures (e.g., `MongoIntegrationFixture`, `ConnectorTestHarness`) live in `../StellaOps.Feedser.Testing`. | ||||
| - Author and review coverage in `../StellaOps.Concelier.Exporter.TrivyDb.Tests`. | ||||
| - Shared fixtures (e.g., `MongoIntegrationFixture`, `ConnectorTestHarness`) live in `../StellaOps.Concelier.Testing`. | ||||
| - Keep fixtures deterministic; match new cases to real-world advisories or regression scenarios. | ||||
| 
 | ||||
| @@ -1,9 +1,9 @@ | ||||
| using System; | ||||
| using System.Threading; | ||||
| using System.Threading.Tasks; | ||||
| using StellaOps.Feedser.Exporter.Json; | ||||
| using StellaOps.Concelier.Exporter.Json; | ||||
| 
 | ||||
| namespace StellaOps.Feedser.Exporter.TrivyDb; | ||||
| namespace StellaOps.Concelier.Exporter.TrivyDb; | ||||
| 
 | ||||
| public interface ITrivyDbBuilder | ||||
| { | ||||
| @@ -1,7 +1,7 @@ | ||||
| using System.Threading; | ||||
| using System.Threading.Tasks; | ||||
| 
 | ||||
| namespace StellaOps.Feedser.Exporter.TrivyDb; | ||||
| namespace StellaOps.Concelier.Exporter.TrivyDb; | ||||
| 
 | ||||
| public interface ITrivyDbOrasPusher | ||||
| { | ||||
| @@ -1,7 +1,7 @@ | ||||
| using System.Collections.Generic; | ||||
| using System.Text.Json.Serialization; | ||||
| 
 | ||||
| namespace StellaOps.Feedser.Exporter.TrivyDb; | ||||
| namespace StellaOps.Concelier.Exporter.TrivyDb; | ||||
| 
 | ||||
| public sealed record OciDescriptor( | ||||
|     [property: JsonPropertyName("mediaType")] string MediaType, | ||||
| @@ -1,7 +1,7 @@ | ||||
| using System.Collections.Generic; | ||||
| using System.Text.Json.Serialization; | ||||
| 
 | ||||
| namespace StellaOps.Feedser.Exporter.TrivyDb; | ||||
| namespace StellaOps.Concelier.Exporter.TrivyDb; | ||||
| 
 | ||||
| public sealed record OciIndex( | ||||
|     [property: JsonPropertyName("schemaVersion")] int SchemaVersion, | ||||
| @@ -1,7 +1,7 @@ | ||||
| using System.Collections.Generic; | ||||
| using System.Text.Json.Serialization; | ||||
| 
 | ||||
| namespace StellaOps.Feedser.Exporter.TrivyDb; | ||||
| namespace StellaOps.Concelier.Exporter.TrivyDb; | ||||
| 
 | ||||
| public sealed record OciManifest( | ||||
|     [property: JsonPropertyName("schemaVersion")] int SchemaVersion, | ||||
| @@ -8,9 +8,9 @@ | ||||
|     <TreatWarningsAsErrors>true</TreatWarningsAsErrors> | ||||
|   </PropertyGroup> | ||||
|   <ItemGroup> | ||||
|     <ProjectReference Include="..\StellaOps.Feedser.Exporter.Json\StellaOps.Feedser.Exporter.Json.csproj" /> | ||||
|     <ProjectReference Include="..\StellaOps.Feedser.Models\StellaOps.Feedser.Models.csproj" /> | ||||
|     <ProjectReference Include="..\StellaOps.Feedser.Storage.Mongo\StellaOps.Feedser.Storage.Mongo.csproj" /> | ||||
|     <ProjectReference Include="..\StellaOps.Concelier.Exporter.Json\StellaOps.Concelier.Exporter.Json.csproj" /> | ||||
|     <ProjectReference Include="..\StellaOps.Concelier.Models\StellaOps.Concelier.Models.csproj" /> | ||||
|     <ProjectReference Include="..\StellaOps.Concelier.Storage.Mongo\StellaOps.Concelier.Storage.Mongo.csproj" /> | ||||
|     <ProjectReference Include="../StellaOps.DependencyInjection/StellaOps.DependencyInjection.csproj" /> | ||||
|     <ProjectReference Include="../StellaOps.Plugin/StellaOps.Plugin.csproj" /> | ||||
|   </ItemGroup> | ||||
| @@ -11,4 +11,4 @@ | ||||
| |ExportState persistence & idempotence|BE-Export|Storage.Mongo|DONE – baseline resets wired into `ExportStateManager`, planner signals resets after delta runs, and exporters update state w/ repository-aware baseline rotation + tests.| | ||||
| |Streamed package building to avoid large copies|BE-Export|Exporters|DONE – metadata/config now reuse backing arrays and OCI writer streams directly without double buffering.| | ||||
| |Plan incremental/delta exports|BE-Export|Exporters|DONE – state captures per-file manifests, planner schedules delta vs full resets, layer reuse smoke test verifies OCI reuse, and operator guide documents the validation flow.| | ||||
| |Advisory schema parity export (description/CWEs/canonical metric)|BE-Export|Models, Core|DONE (2025-10-15) – exporter/test fixtures updated to handle description/CWEs/canonical metric fields during Trivy DB packaging; `dotnet test src/StellaOps.Feedser.Exporter.TrivyDb.Tests` re-run 2025-10-15 to confirm coverage.| | ||||
| |Advisory schema parity export (description/CWEs/canonical metric)|BE-Export|Models, Core|DONE (2025-10-15) – exporter/test fixtures updated to handle description/CWEs/canonical metric fields during Trivy DB packaging; `dotnet test src/StellaOps.Concelier.Exporter.TrivyDb.Tests` re-run 2025-10-15 to confirm coverage.| | ||||
| @@ -1,7 +1,7 @@ | ||||
| using System; | ||||
| using System.Text.Json.Serialization; | ||||
| 
 | ||||
| namespace StellaOps.Feedser.Exporter.TrivyDb; | ||||
| namespace StellaOps.Concelier.Exporter.TrivyDb; | ||||
| 
 | ||||
| public sealed record TrivyConfigDocument( | ||||
|     [property: JsonPropertyName("mediaType")] string MediaType, | ||||
| @@ -4,7 +4,7 @@ using System.Runtime.InteropServices; | ||||
| using System.Threading; | ||||
| using System.Threading.Tasks; | ||||
| 
 | ||||
| namespace StellaOps.Feedser.Exporter.TrivyDb; | ||||
| namespace StellaOps.Concelier.Exporter.TrivyDb; | ||||
| 
 | ||||
| public sealed class TrivyDbBlob | ||||
| { | ||||
| @@ -11,9 +11,9 @@ using System.Threading.Tasks; | ||||
| using System.Formats.Tar; | ||||
| using Microsoft.Extensions.Logging; | ||||
| using Microsoft.Extensions.Options; | ||||
| using StellaOps.Feedser.Exporter.Json; | ||||
| using StellaOps.Concelier.Exporter.Json; | ||||
| 
 | ||||
| namespace StellaOps.Feedser.Exporter.TrivyDb; | ||||
| namespace StellaOps.Concelier.Exporter.TrivyDb; | ||||
| 
 | ||||
| public sealed class TrivyDbBoltBuilder : ITrivyDbBuilder | ||||
| { | ||||
| @@ -1,6 +1,6 @@ | ||||
| using System; | ||||
| 
 | ||||
| namespace StellaOps.Feedser.Exporter.TrivyDb; | ||||
| namespace StellaOps.Concelier.Exporter.TrivyDb; | ||||
| 
 | ||||
| public sealed record TrivyDbBuilderResult( | ||||
|     string ArchivePath, | ||||
| @@ -5,9 +5,9 @@ using System.Text.Json; | ||||
| using System.Threading; | ||||
| using System.Threading.Tasks; | ||||
| using Microsoft.Extensions.Logging; | ||||
| using StellaOps.Feedser.Core.Jobs; | ||||
| using StellaOps.Concelier.Core.Jobs; | ||||
| 
 | ||||
| namespace StellaOps.Feedser.Exporter.TrivyDb; | ||||
| namespace StellaOps.Concelier.Exporter.TrivyDb; | ||||
| 
 | ||||
| public sealed class TrivyDbExportJob : IJob | ||||
| { | ||||
| @@ -1,4 +1,4 @@ | ||||
| namespace StellaOps.Feedser.Exporter.TrivyDb; | ||||
| namespace StellaOps.Concelier.Exporter.TrivyDb; | ||||
| 
 | ||||
| public enum TrivyDbExportMode | ||||
| { | ||||
| @@ -1,15 +1,15 @@ | ||||
| using System; | ||||
| using System.IO; | ||||
| using System.Collections.Generic; | ||||
| using StellaOps.Feedser.Exporter.Json; | ||||
| using StellaOps.Concelier.Exporter.Json; | ||||
| 
 | ||||
| namespace StellaOps.Feedser.Exporter.TrivyDb; | ||||
| namespace StellaOps.Concelier.Exporter.TrivyDb; | ||||
| 
 | ||||
| public sealed class TrivyDbExportOptions | ||||
| { | ||||
|     public string OutputRoot { get; set; } = Path.Combine("exports", "trivy"); | ||||
| 
 | ||||
|     public string ReferencePrefix { get; set; } = "feedser/trivy"; | ||||
|     public string ReferencePrefix { get; set; } = "concelier/trivy"; | ||||
| 
 | ||||
|     public string TagFormat { get; set; } = "yyyyMMdd'T'HHmmss'Z'"; | ||||
| 
 | ||||
| @@ -1,7 +1,7 @@ | ||||
| using System; | ||||
| using System.Threading; | ||||
| 
 | ||||
| namespace StellaOps.Feedser.Exporter.TrivyDb; | ||||
| namespace StellaOps.Concelier.Exporter.TrivyDb; | ||||
| 
 | ||||
| internal sealed record TrivyDbExportOverrides( | ||||
|     bool? PublishFull, | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user