Rename Feedser to Concelier

This commit is contained in:
2025-10-18 20:04:15 +03:00
parent 7e1b10d3b2
commit 0137856fdb
1208 changed files with 4370 additions and 4370 deletions

View File

@@ -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:

View File

@@ -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>

View File

@@ -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'">

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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,

View File

@@ -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);
}

View File

@@ -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");

View File

@@ -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);
}
}

View File

@@ -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));
}

View File

@@ -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);

View File

@@ -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.

View File

@@ -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",

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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. |

View File

@@ -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; }

View File

@@ -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"
}
}
});

View File

@@ -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)

View File

@@ -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.

View File

@@ -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."

View File

@@ -11,7 +11,7 @@ internal static class AuthorityTokenUtilities
var scope = options.Authority?.Scope;
return string.IsNullOrWhiteSpace(scope)
? StellaOpsScopes.FeedserJobsTrigger
? StellaOpsScopes.ConcelierJobsTrigger
: scope.Trim();
}

View File

@@ -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>();

View File

@@ -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;

View File

@@ -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();

View File

@@ -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.|

View File

@@ -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
{

View File

@@ -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
{

View File

@@ -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);

View File

@@ -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
{

View File

@@ -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
{

View File

@@ -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>

View File

@@ -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.

View File

@@ -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.

View File

@@ -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

View File

@@ -1,4 +1,4 @@
namespace StellaOps.Feedser.Core.Jobs;
namespace StellaOps.Concelier.Core.Jobs;
public interface IJob
{

View File

@@ -1,4 +1,4 @@
namespace StellaOps.Feedser.Core.Jobs;
namespace StellaOps.Concelier.Core.Jobs;
public interface IJobCoordinator
{

View File

@@ -1,4 +1,4 @@
namespace StellaOps.Feedser.Core.Jobs;
namespace StellaOps.Concelier.Core.Jobs;
public interface IJobStore
{

View File

@@ -1,4 +1,4 @@
namespace StellaOps.Feedser.Core.Jobs;
namespace StellaOps.Concelier.Core.Jobs;
public interface ILeaseStore
{

View File

@@ -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
{

View File

@@ -1,4 +1,4 @@
namespace StellaOps.Feedser.Core.Jobs;
namespace StellaOps.Concelier.Core.Jobs;
public sealed record JobDefinition(
string Kind,

View File

@@ -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.");
}

View File

@@ -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
{

View File

@@ -1,4 +1,4 @@
namespace StellaOps.Feedser.Core.Jobs;
namespace StellaOps.Concelier.Core.Jobs;
public sealed record JobLease(
string Key,

View File

@@ -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
{

View File

@@ -1,4 +1,4 @@
namespace StellaOps.Feedser.Core.Jobs;
namespace StellaOps.Concelier.Core.Jobs;
public sealed record JobRunCompletion(
JobRunStatus Status,

View File

@@ -1,4 +1,4 @@
namespace StellaOps.Feedser.Core.Jobs;
namespace StellaOps.Concelier.Core.Jobs;
public sealed record JobRunCreateRequest(
string Kind,

View File

@@ -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.

View File

@@ -1,4 +1,4 @@
namespace StellaOps.Feedser.Core.Jobs;
namespace StellaOps.Concelier.Core.Jobs;
public enum JobRunStatus
{

View File

@@ -1,7 +1,7 @@
using System;
using Microsoft.Extensions.DependencyInjection;
namespace StellaOps.Feedser.Core.Jobs;
namespace StellaOps.Concelier.Core.Jobs;
public sealed class JobSchedulerBuilder
{

View File

@@ -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.

View File

@@ -1,4 +1,4 @@
namespace StellaOps.Feedser.Core.Jobs;
namespace StellaOps.Concelier.Core.Jobs;
public sealed class JobSchedulerOptions
{

View File

@@ -1,4 +1,4 @@
namespace StellaOps.Feedser.Core.Jobs;
namespace StellaOps.Concelier.Core.Jobs;
public enum JobTriggerOutcome
{

View File

@@ -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
{

View File

@@ -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>

View File

@@ -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)),
});
}

View File

@@ -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
{

View File

@@ -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]

View File

@@ -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]

View File

@@ -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>

View File

@@ -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
{

View File

@@ -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.

View File

@@ -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
{

View File

@@ -1,7 +1,7 @@
using System;
using System.Reflection;
namespace StellaOps.Feedser.Exporter.Json;
namespace StellaOps.Concelier.Exporter.Json;
public static class ExporterVersion
{

View File

@@ -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
{

View File

@@ -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.

View File

@@ -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
{

View File

@@ -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
{

View File

@@ -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.

View File

@@ -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
{

View File

@@ -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.

View File

@@ -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)
{

View File

@@ -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
{

View File

@@ -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
{

View File

@@ -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>

View File

@@ -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.|

View File

@@ -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.

View File

@@ -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>

View File

@@ -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);

View File

@@ -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");
}

View File

@@ -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
{

View File

@@ -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
{

View File

@@ -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.

View File

@@ -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
{

View File

@@ -1,7 +1,7 @@
using System.Threading;
using System.Threading.Tasks;
namespace StellaOps.Feedser.Exporter.TrivyDb;
namespace StellaOps.Concelier.Exporter.TrivyDb;
public interface ITrivyDbOrasPusher
{

View File

@@ -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,

View File

@@ -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,

View File

@@ -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,

View File

@@ -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>

View File

@@ -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.|

View File

@@ -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,

View File

@@ -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
{

View File

@@ -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
{

View File

@@ -1,6 +1,6 @@
using System;
namespace StellaOps.Feedser.Exporter.TrivyDb;
namespace StellaOps.Concelier.Exporter.TrivyDb;
public sealed record TrivyDbBuilderResult(
string ArchivePath,

View File

@@ -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
{

View File

@@ -1,4 +1,4 @@
namespace StellaOps.Feedser.Exporter.TrivyDb;
namespace StellaOps.Concelier.Exporter.TrivyDb;
public enum TrivyDbExportMode
{

View File

@@ -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'";

View File

@@ -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