Complete batch 012 (golden set diff) and 013 (advisory chat), fix build errors
Sprints completed: - SPRINT_20260110_012_* (golden set diff layer - 10 sprints) - SPRINT_20260110_013_* (advisory chat - 4 sprints) Build fixes applied: - Fix namespace conflicts with Microsoft.Extensions.Options.Options.Create - Fix VexDecisionReachabilityIntegrationTests API drift (major rewrite) - Fix VexSchemaValidationTests FluentAssertions method name - Fix FixChainGateIntegrationTests ambiguous type references - Fix AdvisoryAI test files required properties and namespace aliases - Add stub types for CveMappingController (ICveSymbolMappingService) - Fix VerdictBuilderService static context issue Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,227 @@
|
||||
using System.Collections.Immutable;
|
||||
using System.Globalization;
|
||||
|
||||
using YamlDotNet.Serialization;
|
||||
using YamlDotNet.Serialization.NamingConventions;
|
||||
|
||||
namespace StellaOps.BinaryIndex.GoldenSet;
|
||||
|
||||
/// <summary>
|
||||
/// YAML serialization for golden set definitions.
|
||||
/// Uses snake_case naming convention for human-readability.
|
||||
/// </summary>
|
||||
public static class GoldenSetYamlSerializer
|
||||
{
|
||||
private static readonly IDeserializer Deserializer = new DeserializerBuilder()
|
||||
.WithNamingConvention(UnderscoredNamingConvention.Instance)
|
||||
.IgnoreUnmatchedProperties()
|
||||
.Build();
|
||||
|
||||
private static readonly ISerializer Serializer = new SerializerBuilder()
|
||||
.WithNamingConvention(UnderscoredNamingConvention.Instance)
|
||||
.ConfigureDefaultValuesHandling(DefaultValuesHandling.OmitNull | DefaultValuesHandling.OmitEmptyCollections)
|
||||
.Build();
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes a golden set from YAML content.
|
||||
/// </summary>
|
||||
/// <param name="yaml">YAML content to parse.</param>
|
||||
/// <returns>Parsed golden set definition.</returns>
|
||||
/// <exception cref="InvalidOperationException">Thrown when parsing fails.</exception>
|
||||
public static GoldenSetDefinition Deserialize(string yaml)
|
||||
{
|
||||
ArgumentException.ThrowIfNullOrWhiteSpace(yaml);
|
||||
|
||||
var dto = Deserializer.Deserialize<GoldenSetYamlDto>(yaml)
|
||||
?? throw new InvalidOperationException("Failed to deserialize YAML: result was null");
|
||||
|
||||
return MapToDefinition(dto);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes a golden set to YAML content.
|
||||
/// </summary>
|
||||
/// <param name="definition">Definition to serialize.</param>
|
||||
/// <returns>YAML string representation.</returns>
|
||||
public static string Serialize(GoldenSetDefinition definition)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(definition);
|
||||
|
||||
var dto = MapToDto(definition);
|
||||
return Serializer.Serialize(dto);
|
||||
}
|
||||
|
||||
private static GoldenSetDefinition MapToDefinition(GoldenSetYamlDto dto)
|
||||
{
|
||||
return new GoldenSetDefinition
|
||||
{
|
||||
Id = dto.Id ?? throw new InvalidOperationException("Missing required field: id"),
|
||||
Component = dto.Component ?? throw new InvalidOperationException("Missing required field: component"),
|
||||
Targets = dto.Targets?.Select(MapTargetToDefinition).ToImmutableArray()
|
||||
?? throw new InvalidOperationException("Missing required field: targets"),
|
||||
Witness = dto.Witness is null ? null : MapWitnessToDefinition(dto.Witness),
|
||||
Metadata = dto.Metadata is null
|
||||
? throw new InvalidOperationException("Missing required field: metadata")
|
||||
: MapMetadataToDefinition(dto.Metadata)
|
||||
};
|
||||
}
|
||||
|
||||
private static VulnerableTarget MapTargetToDefinition(VulnerableTargetYamlDto dto)
|
||||
{
|
||||
return new VulnerableTarget
|
||||
{
|
||||
FunctionName = dto.Function ?? throw new InvalidOperationException("Missing required field: function"),
|
||||
Edges = dto.Edges?.Select(e => BasicBlockEdge.Parse(e)).ToImmutableArray() ?? [],
|
||||
Sinks = dto.Sinks?.ToImmutableArray() ?? [],
|
||||
Constants = dto.Constants?.ToImmutableArray() ?? [],
|
||||
TaintInvariant = dto.TaintInvariant,
|
||||
SourceFile = dto.SourceFile,
|
||||
SourceLine = dto.SourceLine
|
||||
};
|
||||
}
|
||||
|
||||
private static WitnessInput MapWitnessToDefinition(WitnessYamlDto dto)
|
||||
{
|
||||
return new WitnessInput
|
||||
{
|
||||
Arguments = dto.Arguments?.ToImmutableArray() ?? [],
|
||||
Invariant = dto.Invariant,
|
||||
PocFileRef = dto.PocFileRef
|
||||
};
|
||||
}
|
||||
|
||||
private static GoldenSetMetadata MapMetadataToDefinition(GoldenSetMetadataYamlDto dto)
|
||||
{
|
||||
return new GoldenSetMetadata
|
||||
{
|
||||
AuthorId = dto.AuthorId ?? throw new InvalidOperationException("Missing required field: metadata.author_id"),
|
||||
CreatedAt = ParseDateTimeOffset(dto.CreatedAt, "metadata.created_at"),
|
||||
SourceRef = dto.SourceRef ?? throw new InvalidOperationException("Missing required field: metadata.source_ref"),
|
||||
ReviewedBy = dto.ReviewedBy,
|
||||
ReviewedAt = string.IsNullOrWhiteSpace(dto.ReviewedAt) ? null : ParseDateTimeOffset(dto.ReviewedAt, "metadata.reviewed_at"),
|
||||
Tags = dto.Tags?.ToImmutableArray() ?? [],
|
||||
SchemaVersion = dto.SchemaVersion ?? GoldenSetConstants.CurrentSchemaVersion
|
||||
};
|
||||
}
|
||||
|
||||
private static DateTimeOffset ParseDateTimeOffset(string? value, string fieldName)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(value))
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
string.Format(CultureInfo.InvariantCulture, "Missing required field: {0}", fieldName));
|
||||
}
|
||||
|
||||
if (!DateTimeOffset.TryParse(value, CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out var result))
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
string.Format(CultureInfo.InvariantCulture, "Invalid date format in {0}: {1}", fieldName, value));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static GoldenSetYamlDto MapToDto(GoldenSetDefinition definition)
|
||||
{
|
||||
return new GoldenSetYamlDto
|
||||
{
|
||||
Id = definition.Id,
|
||||
Component = definition.Component,
|
||||
Targets = definition.Targets.Select(MapTargetToDto).ToList(),
|
||||
Witness = definition.Witness is null ? null : MapWitnessToDto(definition.Witness),
|
||||
Metadata = MapMetadataToDto(definition.Metadata)
|
||||
};
|
||||
}
|
||||
|
||||
private static VulnerableTargetYamlDto MapTargetToDto(VulnerableTarget target)
|
||||
{
|
||||
return new VulnerableTargetYamlDto
|
||||
{
|
||||
Function = target.FunctionName,
|
||||
Edges = target.Edges.IsDefaultOrEmpty ? null : target.Edges.Select(e => e.ToString()).ToList(),
|
||||
Sinks = target.Sinks.IsDefaultOrEmpty ? null : target.Sinks.ToList(),
|
||||
Constants = target.Constants.IsDefaultOrEmpty ? null : target.Constants.ToList(),
|
||||
TaintInvariant = target.TaintInvariant,
|
||||
SourceFile = target.SourceFile,
|
||||
SourceLine = target.SourceLine
|
||||
};
|
||||
}
|
||||
|
||||
private static WitnessYamlDto MapWitnessToDto(WitnessInput witness)
|
||||
{
|
||||
return new WitnessYamlDto
|
||||
{
|
||||
Arguments = witness.Arguments.IsDefaultOrEmpty ? null : witness.Arguments.ToList(),
|
||||
Invariant = witness.Invariant,
|
||||
PocFileRef = witness.PocFileRef
|
||||
};
|
||||
}
|
||||
|
||||
private static GoldenSetMetadataYamlDto MapMetadataToDto(GoldenSetMetadata metadata)
|
||||
{
|
||||
return new GoldenSetMetadataYamlDto
|
||||
{
|
||||
AuthorId = metadata.AuthorId,
|
||||
CreatedAt = metadata.CreatedAt.ToString("O", CultureInfo.InvariantCulture),
|
||||
SourceRef = metadata.SourceRef,
|
||||
ReviewedBy = metadata.ReviewedBy,
|
||||
ReviewedAt = metadata.ReviewedAt?.ToString("O", CultureInfo.InvariantCulture),
|
||||
Tags = metadata.Tags.IsDefaultOrEmpty ? null : metadata.Tags.ToList(),
|
||||
SchemaVersion = metadata.SchemaVersion
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#region YAML DTOs
|
||||
|
||||
/// <summary>
|
||||
/// YAML DTO for golden set definition.
|
||||
/// </summary>
|
||||
internal sealed class GoldenSetYamlDto
|
||||
{
|
||||
public string? Id { get; set; }
|
||||
public string? Component { get; set; }
|
||||
public List<VulnerableTargetYamlDto>? Targets { get; set; }
|
||||
public WitnessYamlDto? Witness { get; set; }
|
||||
public GoldenSetMetadataYamlDto? Metadata { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// YAML DTO for vulnerable target.
|
||||
/// </summary>
|
||||
internal sealed class VulnerableTargetYamlDto
|
||||
{
|
||||
public string? Function { get; set; }
|
||||
public List<string>? Edges { get; set; }
|
||||
public List<string>? Sinks { get; set; }
|
||||
public List<string>? Constants { get; set; }
|
||||
public string? TaintInvariant { get; set; }
|
||||
public string? SourceFile { get; set; }
|
||||
public int? SourceLine { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// YAML DTO for witness input.
|
||||
/// </summary>
|
||||
internal sealed class WitnessYamlDto
|
||||
{
|
||||
public List<string>? Arguments { get; set; }
|
||||
public string? Invariant { get; set; }
|
||||
public string? PocFileRef { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// YAML DTO for metadata.
|
||||
/// </summary>
|
||||
internal sealed class GoldenSetMetadataYamlDto
|
||||
{
|
||||
public string? AuthorId { get; set; }
|
||||
public string? CreatedAt { get; set; }
|
||||
public string? SourceRef { get; set; }
|
||||
public string? ReviewedBy { get; set; }
|
||||
public string? ReviewedAt { get; set; }
|
||||
public List<string>? Tags { get; set; }
|
||||
public string? SchemaVersion { get; set; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
Reference in New Issue
Block a user