search and ai stabilization work, localization stablized.
This commit is contained in:
@@ -13,6 +13,7 @@ using StellaOps.Concelier.Core.Canonical;
|
||||
using StellaOps.Concelier.Interest;
|
||||
using StellaOps.Concelier.Merge.Backport;
|
||||
using StellaOps.Concelier.WebService.Results;
|
||||
using static StellaOps.Localization.T;
|
||||
|
||||
namespace StellaOps.Concelier.WebService.Extensions;
|
||||
|
||||
@@ -42,7 +43,7 @@ internal static class CanonicalAdvisoryEndpointExtensions
|
||||
|
||||
if (canonical is null)
|
||||
{
|
||||
return HttpResults.NotFound(new { error = "Canonical advisory not found", id });
|
||||
return HttpResults.NotFound(new { error = _t("concelier.error.advisory_not_found"), id });
|
||||
}
|
||||
|
||||
// Fetch interest score if scoring service is available
|
||||
@@ -140,17 +141,17 @@ internal static class CanonicalAdvisoryEndpointExtensions
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(source))
|
||||
{
|
||||
return HttpResults.BadRequest(new { error = "Source is required" });
|
||||
return HttpResults.BadRequest(new { error = _t("concelier.validation.source_required") });
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(request.Cve))
|
||||
{
|
||||
return HttpResults.BadRequest(new { error = "CVE is required" });
|
||||
return HttpResults.BadRequest(new { error = _t("concelier.validation.cve_required") });
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(request.AffectsKey))
|
||||
{
|
||||
return HttpResults.BadRequest(new { error = "AffectsKey is required" });
|
||||
return HttpResults.BadRequest(new { error = _t("concelier.validation.affects_key_required") });
|
||||
}
|
||||
|
||||
var rawAdvisory = new RawAdvisory
|
||||
@@ -204,15 +205,15 @@ internal static class CanonicalAdvisoryEndpointExtensions
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(source))
|
||||
{
|
||||
return HttpResults.BadRequest(new { error = "Source is required" });
|
||||
return HttpResults.BadRequest(new { error = _t("concelier.validation.source_required") });
|
||||
}
|
||||
|
||||
var defaultFetchedAt = timeProvider.GetUtcNow();
|
||||
var rawAdvisories = requests.Select(request => new RawAdvisory
|
||||
{
|
||||
SourceAdvisoryId = request.SourceAdvisoryId ?? $"{source.ToUpperInvariant()}-{request.Cve}",
|
||||
Cve = request.Cve ?? throw new InvalidOperationException("CVE is required"),
|
||||
AffectsKey = request.AffectsKey ?? throw new InvalidOperationException("AffectsKey is required"),
|
||||
Cve = request.Cve ?? throw new InvalidOperationException(_t("concelier.validation.cve_required")),
|
||||
AffectsKey = request.AffectsKey ?? throw new InvalidOperationException(_t("concelier.validation.affects_key_required")),
|
||||
VersionRangeJson = request.VersionRangeJson,
|
||||
Weaknesses = request.Weaknesses ?? [],
|
||||
PatchLineage = request.PatchLineage,
|
||||
@@ -266,7 +267,7 @@ internal static class CanonicalAdvisoryEndpointExtensions
|
||||
{
|
||||
if (!Enum.TryParse<CanonicalStatus>(request.Status, true, out var status))
|
||||
{
|
||||
return HttpResults.BadRequest(new { error = "Invalid status", validValues = Enum.GetNames<CanonicalStatus>() });
|
||||
return HttpResults.BadRequest(new { error = _t("concelier.validation.invalid_status"), validValues = Enum.GetNames<CanonicalStatus>() });
|
||||
}
|
||||
|
||||
await service.UpdateStatusAsync(id, status, ct).ConfigureAwait(false);
|
||||
@@ -292,7 +293,7 @@ internal static class CanonicalAdvisoryEndpointExtensions
|
||||
var canonical = await canonicalService.GetByIdAsync(id, ct).ConfigureAwait(false);
|
||||
if (canonical is null)
|
||||
{
|
||||
return HttpResults.NotFound(new { error = "Canonical advisory not found", id });
|
||||
return HttpResults.NotFound(new { error = _t("concelier.error.advisory_not_found"), id });
|
||||
}
|
||||
|
||||
if (provenanceService is null)
|
||||
|
||||
@@ -9,6 +9,7 @@ using StellaOps.Concelier.Federation.Models;
|
||||
using StellaOps.Concelier.WebService.Options;
|
||||
using StellaOps.Concelier.WebService.Results;
|
||||
using System.Globalization;
|
||||
using static StellaOps.Localization.T;
|
||||
|
||||
namespace StellaOps.Concelier.WebService.Extensions;
|
||||
|
||||
@@ -45,12 +46,12 @@ internal static class FederationEndpointExtensions
|
||||
// Validate parameters
|
||||
if (maxItems < 1 || maxItems > 100_000)
|
||||
{
|
||||
return HttpResults.BadRequest(new { error = "max_items must be between 1 and 100000" });
|
||||
return HttpResults.BadRequest(new { error = _t("concelier.validation.max_items_range") });
|
||||
}
|
||||
|
||||
if (compressLevel < 1 || compressLevel > 19)
|
||||
{
|
||||
return HttpResults.BadRequest(new { error = "compress_level must be between 1 and 19" });
|
||||
return HttpResults.BadRequest(new { error = _t("concelier.validation.compress_level_range") });
|
||||
}
|
||||
|
||||
var exportOptions = new BundleExportOptions
|
||||
@@ -170,7 +171,7 @@ internal static class FederationEndpointExtensions
|
||||
(!contentType.Contains("application/zstd") &&
|
||||
!contentType.Contains("application/octet-stream")))
|
||||
{
|
||||
return HttpResults.BadRequest(new { error = "Content-Type must be application/zstd or application/octet-stream" });
|
||||
return HttpResults.BadRequest(new { error = _t("concelier.validation.content_type_zstd") });
|
||||
}
|
||||
|
||||
// Parse conflict resolution
|
||||
@@ -179,7 +180,7 @@ internal static class FederationEndpointExtensions
|
||||
{
|
||||
if (!Enum.TryParse<ConflictResolution>(onConflict, ignoreCase: true, out conflictResolution))
|
||||
{
|
||||
return HttpResults.BadRequest(new { error = "on_conflict must be one of: PreferRemote, PreferLocal, Fail" });
|
||||
return HttpResults.BadRequest(new { error = _t("concelier.validation.on_conflict_values") });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -388,7 +389,7 @@ internal static class FederationEndpointExtensions
|
||||
var site = await ledgerRepository.GetPolicyAsync(siteId, cancellationToken);
|
||||
if (site == null)
|
||||
{
|
||||
return HttpResults.NotFound(new { error = $"Site '{siteId}' not found" });
|
||||
return HttpResults.NotFound(new { error = _t("concelier.error.site_not_found", siteId) });
|
||||
}
|
||||
|
||||
// Get recent sync history
|
||||
|
||||
@@ -11,6 +11,7 @@ using Microsoft.AspNetCore.Mvc;
|
||||
using StellaOps.Auth.ServerIntegration.Tenancy;
|
||||
using StellaOps.Concelier.Interest;
|
||||
using StellaOps.Concelier.Interest.Models;
|
||||
using static StellaOps.Localization.T;
|
||||
|
||||
namespace StellaOps.Concelier.WebService.Extensions;
|
||||
|
||||
@@ -37,7 +38,7 @@ internal static class InterestScoreEndpointExtensions
|
||||
var score = await scoringService.GetScoreAsync(id, ct).ConfigureAwait(false);
|
||||
|
||||
return score is null
|
||||
? HttpResults.NotFound(new { error = "Interest score not found", canonicalId = id })
|
||||
? HttpResults.NotFound(new { error = _t("concelier.error.interest_score_not_found"), canonicalId = id })
|
||||
: HttpResults.Ok(MapToResponse(score));
|
||||
})
|
||||
.WithName("GetInterestScore")
|
||||
|
||||
@@ -11,6 +11,7 @@ using Microsoft.AspNetCore.Mvc;
|
||||
using StellaOps.Auth.ServerIntegration.Tenancy;
|
||||
using StellaOps.Concelier.SbomIntegration;
|
||||
using StellaOps.Concelier.SbomIntegration.Models;
|
||||
using static StellaOps.Localization.T;
|
||||
|
||||
namespace StellaOps.Concelier.WebService.Extensions;
|
||||
|
||||
@@ -73,7 +74,7 @@ internal static class SbomEndpointExtensions
|
||||
var registration = await registryService.GetByDigestAsync(digest, ct).ConfigureAwait(false);
|
||||
if (registration is null)
|
||||
{
|
||||
return HttpResults.NotFound(new { error = "SBOM not found", digest });
|
||||
return HttpResults.NotFound(new { error = _t("concelier.error.sbom_not_found"), digest });
|
||||
}
|
||||
|
||||
var matches = await registryService.GetMatchesAsync(digest, ct).ConfigureAwait(false);
|
||||
@@ -156,7 +157,7 @@ internal static class SbomEndpointExtensions
|
||||
|
||||
if (registration is null)
|
||||
{
|
||||
return HttpResults.NotFound(new { error = "SBOM not found", digest });
|
||||
return HttpResults.NotFound(new { error = _t("concelier.error.sbom_not_found"), digest });
|
||||
}
|
||||
|
||||
return HttpResults.Ok(new SbomDetailResponse
|
||||
|
||||
@@ -57,6 +57,7 @@ using StellaOps.Configuration;
|
||||
using StellaOps.Plugin.DependencyInjection;
|
||||
using StellaOps.Plugin.Hosting;
|
||||
using StellaOps.Provenance;
|
||||
using StellaOps.Localization;
|
||||
using StellaOps.Router.AspNet;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -841,6 +842,8 @@ builder.Services.RegisterPluginRoutines(builder.Configuration, pluginHostOptions
|
||||
builder.Services.AddEndpointsApiExplorer();
|
||||
builder.Services.AddStellaOpsCors(builder.Environment, builder.Configuration);
|
||||
builder.Services.AddStellaOpsTenantServices();
|
||||
builder.Services.AddStellaOpsLocalization(builder.Configuration);
|
||||
builder.Services.AddTranslationBundle(System.Reflection.Assembly.GetExecutingAssembly());
|
||||
|
||||
builder.TryAddStellaOpsLocalBinding("concelier");
|
||||
var app = builder.Build();
|
||||
@@ -875,6 +878,7 @@ if (resolvedAuthority.Enabled && resolvedAuthority.AllowAnonymousFallback)
|
||||
}
|
||||
|
||||
app.UseStellaOpsCors();
|
||||
app.UseStellaOpsLocalization();
|
||||
|
||||
if (authorityConfigured)
|
||||
{
|
||||
@@ -4431,6 +4435,7 @@ app.MapGet("/v1/signals/symbols/exists/{advisoryId}", async (
|
||||
// Refresh Router endpoint cache after all endpoints are registered
|
||||
app.TryRefreshStellaRouterEndpoints(routerEnabled);
|
||||
|
||||
await app.LoadTranslationsAsync();
|
||||
await app.RunAsync();
|
||||
}
|
||||
|
||||
|
||||
@@ -46,6 +46,10 @@
|
||||
ReferenceOutputAssembly="false" />
|
||||
<ProjectReference Include="../../Router/__Libraries/StellaOps.Router.AspNet/StellaOps.Router.AspNet.csproj" />
|
||||
<ProjectReference Include="../../__Libraries/StellaOps.Replay.Core/StellaOps.Replay.Core.csproj" />
|
||||
<ProjectReference Include="../../__Libraries/StellaOps.Localization/StellaOps.Localization.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Translations\*.json" />
|
||||
</ItemGroup>
|
||||
<!-- Federation files excluded from Core due to circular dependency; compiled here for DI registration -->
|
||||
<ItemGroup>
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"_meta": { "locale": "en-US", "namespace": "concelier", "version": "1.0" },
|
||||
|
||||
"concelier.error.advisory_not_found": "Canonical advisory not found.",
|
||||
"concelier.error.sbom_not_found": "SBOM not found.",
|
||||
"concelier.error.interest_score_not_found": "Interest score not found.",
|
||||
"concelier.error.site_not_found": "Site '{0}' not found.",
|
||||
|
||||
"concelier.validation.source_required": "source is required.",
|
||||
"concelier.validation.cve_required": "CVE is required.",
|
||||
"concelier.validation.affects_key_required": "affectsKey is required.",
|
||||
"concelier.validation.invalid_status": "Invalid status.",
|
||||
"concelier.validation.max_items_range": "max_items must be between 1 and 100000.",
|
||||
"concelier.validation.compress_level_range": "compress_level must be between 1 and 19.",
|
||||
"concelier.validation.content_type_zstd": "Content-Type must be application/zstd or application/octet-stream.",
|
||||
"concelier.validation.on_conflict_values": "on_conflict must be one of: PreferRemote, PreferLocal, Fail."
|
||||
}
|
||||
Reference in New Issue
Block a user