Rename Feedser to Concelier
This commit is contained in:
		
							
								
								
									
										166
									
								
								src/StellaOps.Concelier.Models/AliasSchemeRegistry.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										166
									
								
								src/StellaOps.Concelier.Models/AliasSchemeRegistry.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,166 @@ | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Collections.Immutable; | ||||
| using System.Linq; | ||||
| using System.Text.RegularExpressions; | ||||
|  | ||||
| namespace StellaOps.Concelier.Models; | ||||
|  | ||||
| public static class AliasSchemeRegistry | ||||
| { | ||||
|     private sealed record AliasScheme( | ||||
|         string Name, | ||||
|         Func<string?, bool> Predicate, | ||||
|         Func<string?, string> Normalizer); | ||||
|  | ||||
| private static readonly AliasScheme[] SchemeDefinitions = | ||||
|     { | ||||
|         BuildScheme(AliasSchemes.Cve, alias => alias is not null && Matches(CvERegex, alias), alias => alias is null ? string.Empty : NormalizePrefix(alias, "CVE")), | ||||
|         BuildScheme(AliasSchemes.Ghsa, alias => alias is not null && Matches(GhsaRegex, alias), alias => alias is null ? string.Empty : NormalizePrefix(alias, "GHSA")), | ||||
|         BuildScheme(AliasSchemes.OsV, alias => alias is not null && Matches(OsVRegex, alias), alias => alias is null ? string.Empty : NormalizePrefix(alias, "OSV")), | ||||
|         BuildScheme(AliasSchemes.Jvn, alias => alias is not null && Matches(JvnRegex, alias), alias => alias is null ? string.Empty : NormalizePrefix(alias, "JVN")), | ||||
|         BuildScheme(AliasSchemes.Jvndb, alias => alias is not null && Matches(JvndbRegex, alias), alias => alias is null ? string.Empty : NormalizePrefix(alias, "JVNDB")), | ||||
|         BuildScheme(AliasSchemes.Bdu, alias => alias is not null && Matches(BduRegex, alias), alias => alias is null ? string.Empty : NormalizePrefix(alias, "BDU")), | ||||
|         BuildScheme(AliasSchemes.Vu, alias => alias is not null && alias.StartsWith("VU#", StringComparison.OrdinalIgnoreCase), alias => NormalizePrefix(alias, "VU", preserveSeparator: '#')), | ||||
|         BuildScheme(AliasSchemes.Msrc, alias => alias is not null && alias.StartsWith("MSRC-", StringComparison.OrdinalIgnoreCase), alias => NormalizePrefix(alias, "MSRC")), | ||||
|         BuildScheme(AliasSchemes.CiscoSa, alias => alias is not null && alias.StartsWith("CISCO-SA-", StringComparison.OrdinalIgnoreCase), alias => NormalizePrefix(alias, "CISCO-SA")), | ||||
|         BuildScheme(AliasSchemes.OracleCpu, alias => alias is not null && alias.StartsWith("ORACLE-CPU", StringComparison.OrdinalIgnoreCase), alias => NormalizePrefix(alias, "ORACLE-CPU")), | ||||
|         BuildScheme(AliasSchemes.Apsb, alias => alias is not null && alias.StartsWith("APSB-", StringComparison.OrdinalIgnoreCase), alias => NormalizePrefix(alias, "APSB")), | ||||
|         BuildScheme(AliasSchemes.Apa, alias => alias is not null && alias.StartsWith("APA-", StringComparison.OrdinalIgnoreCase), alias => NormalizePrefix(alias, "APA")), | ||||
|         BuildScheme(AliasSchemes.AppleHt, alias => alias is not null && alias.StartsWith("APPLE-HT", StringComparison.OrdinalIgnoreCase), alias => NormalizePrefix(alias, "APPLE-HT")), | ||||
|         BuildScheme(AliasSchemes.ChromiumPost, alias => alias is not null && (alias.StartsWith("CHROMIUM-POST", StringComparison.OrdinalIgnoreCase) || alias.StartsWith("CHROMIUM:", StringComparison.OrdinalIgnoreCase)), NormalizeChromium), | ||||
|         BuildScheme(AliasSchemes.Vmsa, alias => alias is not null && alias.StartsWith("VMSA-", StringComparison.OrdinalIgnoreCase), alias => NormalizePrefix(alias, "VMSA")), | ||||
|         BuildScheme(AliasSchemes.Rhsa, alias => alias is not null && alias.StartsWith("RHSA-", StringComparison.OrdinalIgnoreCase), alias => NormalizePrefix(alias, "RHSA")), | ||||
|         BuildScheme(AliasSchemes.Usn, alias => alias is not null && alias.StartsWith("USN-", StringComparison.OrdinalIgnoreCase), alias => NormalizePrefix(alias, "USN")), | ||||
|         BuildScheme(AliasSchemes.Dsa, alias => alias is not null && alias.StartsWith("DSA-", StringComparison.OrdinalIgnoreCase), alias => NormalizePrefix(alias, "DSA")), | ||||
|         BuildScheme(AliasSchemes.SuseSu, alias => alias is not null && alias.StartsWith("SUSE-SU-", StringComparison.OrdinalIgnoreCase), alias => NormalizePrefix(alias, "SUSE-SU")), | ||||
|         BuildScheme(AliasSchemes.Icsa, alias => alias is not null && alias.StartsWith("ICSA-", StringComparison.OrdinalIgnoreCase), alias => NormalizePrefix(alias, "ICSA")), | ||||
|         BuildScheme(AliasSchemes.Cwe, alias => alias is not null && Matches(CweRegex, alias), alias => alias is null ? string.Empty : NormalizePrefix(alias, "CWE")), | ||||
|         BuildScheme(AliasSchemes.Cpe, alias => alias is not null && alias.StartsWith("cpe:", StringComparison.OrdinalIgnoreCase), alias => NormalizePrefix(alias, "cpe", uppercase:false)), | ||||
|         BuildScheme(AliasSchemes.Purl, alias => alias is not null && alias.StartsWith("pkg:", StringComparison.OrdinalIgnoreCase), alias => NormalizePrefix(alias, "pkg", uppercase:false)), | ||||
|     }; | ||||
|  | ||||
|     private static AliasScheme BuildScheme(string name, Func<string?, bool> predicate, Func<string?, string> normalizer) | ||||
|         => new( | ||||
|             name, | ||||
|             predicate, | ||||
|             alias => normalizer(alias)); | ||||
|  | ||||
|     private static readonly ImmutableHashSet<string> SchemeNames = SchemeDefinitions | ||||
|         .Select(static scheme => scheme.Name) | ||||
|         .ToImmutableHashSet(StringComparer.OrdinalIgnoreCase); | ||||
|  | ||||
|     private static readonly Regex CvERegex = new("^CVE-\\d{4}-\\d{4,}$", RegexOptions.Compiled | RegexOptions.CultureInvariant | RegexOptions.IgnoreCase); | ||||
|     private static readonly Regex GhsaRegex = new("^GHSA-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{4}$", RegexOptions.Compiled | RegexOptions.CultureInvariant | RegexOptions.IgnoreCase); | ||||
|     private static readonly Regex OsVRegex = new("^OSV-\\d{4}-\\d+$", RegexOptions.Compiled | RegexOptions.CultureInvariant | RegexOptions.IgnoreCase); | ||||
|     private static readonly Regex JvnRegex = new("^JVN-\\d{4}-\\d{6}$", RegexOptions.Compiled | RegexOptions.CultureInvariant | RegexOptions.IgnoreCase); | ||||
|     private static readonly Regex JvndbRegex = new("^JVNDB-\\d{4}-\\d{6}$", RegexOptions.Compiled | RegexOptions.CultureInvariant | RegexOptions.IgnoreCase); | ||||
|     private static readonly Regex BduRegex = new("^BDU-\\d{4}-\\d+$", RegexOptions.Compiled | RegexOptions.CultureInvariant | RegexOptions.IgnoreCase); | ||||
|     private static readonly Regex CweRegex = new("^CWE-\\d+$", RegexOptions.Compiled | RegexOptions.CultureInvariant | RegexOptions.IgnoreCase); | ||||
|  | ||||
|     public static IReadOnlyCollection<string> KnownSchemes => SchemeNames; | ||||
|  | ||||
|     public static bool IsKnownScheme(string? scheme) | ||||
|         => !string.IsNullOrWhiteSpace(scheme) && SchemeNames.Contains(scheme); | ||||
|  | ||||
|     public static bool TryGetScheme(string? alias, out string scheme) | ||||
|     { | ||||
|         if (string.IsNullOrWhiteSpace(alias)) | ||||
|         { | ||||
|             scheme = string.Empty; | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         var candidate = alias.Trim(); | ||||
|         foreach (var entry in SchemeDefinitions) | ||||
|         { | ||||
|             if (entry.Predicate(candidate)) | ||||
|             { | ||||
|                 scheme = entry.Name; | ||||
|                 return true; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         scheme = string.Empty; | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     public static bool TryNormalize(string? alias, out string normalized, out string scheme) | ||||
|     { | ||||
|         normalized = string.Empty; | ||||
|         scheme = string.Empty; | ||||
|  | ||||
|         if (string.IsNullOrWhiteSpace(alias)) | ||||
|         { | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         var candidate = alias.Trim(); | ||||
|         foreach (var entry in SchemeDefinitions) | ||||
|         { | ||||
|             if (entry.Predicate(candidate)) | ||||
|             { | ||||
|                 scheme = entry.Name; | ||||
|                 normalized = entry.Normalizer(candidate); | ||||
|                 return true; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         normalized = candidate; | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     private static string NormalizePrefix(string? alias, string prefix, bool uppercase = true, char? preserveSeparator = null) | ||||
|     { | ||||
|         if (string.IsNullOrWhiteSpace(alias)) | ||||
|         { | ||||
|             return string.Empty; | ||||
|         } | ||||
|  | ||||
|         var comparison = StringComparison.OrdinalIgnoreCase; | ||||
|         if (!alias.StartsWith(prefix, comparison)) | ||||
|         { | ||||
|             return uppercase ? alias : alias.ToLowerInvariant(); | ||||
|         } | ||||
|  | ||||
|         var remainder = alias[prefix.Length..]; | ||||
|         if (preserveSeparator is { } separator && remainder.Length > 0 && remainder[0] != separator) | ||||
|         { | ||||
|             // Edge case: alias is expected to use a specific separator but does not – return unchanged. | ||||
|             return uppercase ? prefix.ToUpperInvariant() + remainder : prefix + remainder; | ||||
|         } | ||||
|  | ||||
|         var normalizedPrefix = uppercase ? prefix.ToUpperInvariant() : prefix.ToLowerInvariant(); | ||||
|         return normalizedPrefix + remainder; | ||||
|     } | ||||
|  | ||||
|     private static string NormalizeChromium(string? alias) | ||||
|     { | ||||
|         if (string.IsNullOrWhiteSpace(alias)) | ||||
|         { | ||||
|             return string.Empty; | ||||
|         } | ||||
|  | ||||
|         if (alias.StartsWith("CHROMIUM-POST", StringComparison.OrdinalIgnoreCase)) | ||||
|         { | ||||
|             return NormalizePrefix(alias, "CHROMIUM-POST"); | ||||
|         } | ||||
|  | ||||
|         if (alias.StartsWith("CHROMIUM:", StringComparison.OrdinalIgnoreCase)) | ||||
|         { | ||||
|             var remainder = alias["CHROMIUM".Length..]; | ||||
|             return "CHROMIUM" + remainder; | ||||
|         } | ||||
|  | ||||
|         return alias; | ||||
|     } | ||||
|     private static bool Matches(Regex? regex, string? candidate) | ||||
|     { | ||||
|         if (regex is null || string.IsNullOrWhiteSpace(candidate)) | ||||
|         { | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         return regex.IsMatch(candidate); | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user