using System.Text.Json;
using System.Text.Json.Serialization;
using StellaOps.Symbols.Core.Models;
namespace StellaOps.Symbols.Ingestor.Cli;
///
/// Writes symbol manifests to various formats.
///
public static class ManifestWriter
{
private static readonly JsonSerializerOptions JsonOptions = new()
{
WriteIndented = true,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
Converters = { new JsonStringEnumConverter() },
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
};
///
/// Writes manifest to JSON file.
///
public static async Task WriteJsonAsync(
SymbolManifest manifest,
string outputDir,
CancellationToken cancellationToken = default)
{
Directory.CreateDirectory(outputDir);
var fileName = $"{manifest.DebugId}.symbols.json";
var filePath = Path.Combine(outputDir, fileName);
var json = JsonSerializer.Serialize(manifest, JsonOptions);
await File.WriteAllTextAsync(filePath, json, cancellationToken).ConfigureAwait(false);
return filePath;
}
///
/// Writes DSSE envelope to file.
///
public static async Task WriteDsseAsync(
string payload,
string payloadType,
string signature,
string keyId,
string outputDir,
string debugId,
CancellationToken cancellationToken = default)
{
Directory.CreateDirectory(outputDir);
var envelope = new DsseEnvelope
{
PayloadType = payloadType,
Payload = Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(payload)),
Signatures =
[
new DsseSignature { KeyId = keyId, Sig = signature }
]
};
var fileName = $"{debugId}.symbols.dsse.json";
var filePath = Path.Combine(outputDir, fileName);
var json = JsonSerializer.Serialize(envelope, JsonOptions);
await File.WriteAllTextAsync(filePath, json, cancellationToken).ConfigureAwait(false);
return filePath;
}
///
/// Reads manifest from JSON file.
///
public static async Task ReadJsonAsync(
string filePath,
CancellationToken cancellationToken = default)
{
var json = await File.ReadAllTextAsync(filePath, cancellationToken).ConfigureAwait(false);
return JsonSerializer.Deserialize(json, JsonOptions);
}
}
///
/// DSSE envelope structure.
///
public sealed class DsseEnvelope
{
[JsonPropertyName("payloadType")]
public string PayloadType { get; set; } = string.Empty;
[JsonPropertyName("payload")]
public string Payload { get; set; } = string.Empty;
[JsonPropertyName("signatures")]
public List Signatures { get; set; } = [];
}
///
/// DSSE signature.
///
public sealed class DsseSignature
{
[JsonPropertyName("keyid")]
public string KeyId { get; set; } = string.Empty;
[JsonPropertyName("sig")]
public string Sig { get; set; } = string.Empty;
}