Implement Advisory Canonicalization and Backfill Migration
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled

- Added AdvisoryCanonicalizer for canonicalizing advisory identifiers.
- Created EnsureAdvisoryCanonicalKeyBackfillMigration to populate advisory_key and links in advisory_raw documents.
- Introduced FileSurfaceManifestStore for managing surface manifests with file system backing.
- Developed ISurfaceManifestReader and ISurfaceManifestWriter interfaces for reading and writing manifests.
- Implemented SurfaceManifestPathBuilder for constructing paths and URIs for surface manifests.
- Added tests for FileSurfaceManifestStore to ensure correct functionality and deterministic behavior.
- Updated documentation for new features and migration steps.
This commit is contained in:
master
2025-11-07 19:54:02 +02:00
parent a1ce3f74fa
commit 515975edc5
42 changed files with 1893 additions and 336 deletions

View File

@@ -1,21 +1,23 @@
using System.Collections.Immutable;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace StellaOps.Concelier.RawModels;
public sealed record AdvisoryRawDocument(
[property: JsonPropertyName("tenant")] string Tenant,
[property: JsonPropertyName("source")] RawSourceMetadata Source,
[property: JsonPropertyName("upstream")] RawUpstreamMetadata Upstream,
[property: JsonPropertyName("content")] RawContent Content,
[property: JsonPropertyName("identifiers")] RawIdentifiers Identifiers,
[property: JsonPropertyName("linkset")] RawLinkset Linkset,
[property: JsonPropertyName("supersedes")] string? Supersedes = null)
{
public AdvisoryRawDocument WithSupersedes(string supersedes)
=> this with { Supersedes = supersedes };
}
using System.Collections.Immutable;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace StellaOps.Concelier.RawModels;
public sealed record AdvisoryRawDocument(
[property: JsonPropertyName("tenant")] string Tenant,
[property: JsonPropertyName("source")] RawSourceMetadata Source,
[property: JsonPropertyName("upstream")] RawUpstreamMetadata Upstream,
[property: JsonPropertyName("content")] RawContent Content,
[property: JsonPropertyName("identifiers")] RawIdentifiers Identifiers,
[property: JsonPropertyName("linkset")] RawLinkset Linkset,
[property: JsonPropertyName("advisory_key")] string AdvisoryKey = "",
[property: JsonPropertyName("links")] ImmutableArray<RawLink> Links = default,
[property: JsonPropertyName("supersedes")] string? Supersedes = null)
{
public AdvisoryRawDocument WithSupersedes(string supersedes)
=> this with { Supersedes = supersedes };
}
public sealed record RawSourceMetadata(
[property: JsonPropertyName("vendor")] string Vendor,
@@ -49,10 +51,10 @@ public sealed record RawIdentifiers(
[property: JsonPropertyName("aliases")] ImmutableArray<string> Aliases,
[property: JsonPropertyName("primary")] string PrimaryId);
public sealed record RawLinkset
{
[JsonPropertyName("aliases")]
public ImmutableArray<string> Aliases { get; init; } = ImmutableArray<string>.Empty;
public sealed record RawLinkset
{
[JsonPropertyName("aliases")]
public ImmutableArray<string> Aliases { get; init; } = ImmutableArray<string>.Empty;
[JsonPropertyName("purls")]
public ImmutableArray<string> PackageUrls { get; init; } = ImmutableArray<string>.Empty;
@@ -68,9 +70,13 @@ public sealed record RawLinkset
[JsonPropertyName("notes")]
public ImmutableDictionary<string, string> Notes { get; init; } = ImmutableDictionary<string, string>.Empty;
}
public sealed record RawReference(
[property: JsonPropertyName("type")] string Type,
[property: JsonPropertyName("url")] string Url,
[property: JsonPropertyName("source")] string? Source = null);
}
public sealed record RawReference(
[property: JsonPropertyName("type")] string Type,
[property: JsonPropertyName("url")] string Url,
[property: JsonPropertyName("source")] string? Source = null);
public sealed record RawLink(
[property: JsonPropertyName("scheme")] string Scheme,
[property: JsonPropertyName("value")] string Value);

View File

@@ -5,18 +5,21 @@ namespace StellaOps.Concelier.RawModels;
public static class RawDocumentFactory
{
public static AdvisoryRawDocument CreateAdvisory(
string tenant,
RawSourceMetadata source,
RawUpstreamMetadata upstream,
RawContent content,
RawIdentifiers identifiers,
RawLinkset linkset,
string? supersedes = null)
{
var clonedContent = content with { Raw = Clone(content.Raw) };
return new AdvisoryRawDocument(tenant, source, upstream, clonedContent, identifiers, linkset, supersedes);
}
public static AdvisoryRawDocument CreateAdvisory(
string tenant,
RawSourceMetadata source,
RawUpstreamMetadata upstream,
RawContent content,
RawIdentifiers identifiers,
RawLinkset linkset,
string advisoryKey,
ImmutableArray<RawLink> links,
string? supersedes = null)
{
var clonedContent = content with { Raw = Clone(content.Raw) };
var normalizedLinks = links.IsDefault ? ImmutableArray<RawLink>.Empty : links;
return new AdvisoryRawDocument(tenant, source, upstream, clonedContent, identifiers, linkset, advisoryKey, normalizedLinks, supersedes);
}
public static VexRawDocument CreateVex(
string tenant,