using System; using System.Collections.Generic; using System.Text.Json; namespace StellaOps.Provenance; public static partial class ProvenanceJsonParser { private static DsseProvenance ParseDsse(JsonElement root) { if (!root.TryGetProperty("dsse", out var dsseElement) || dsseElement.ValueKind != JsonValueKind.Object) { throw new InvalidOperationException("Provenance metadata missing dsse block."); } var keyElement = GetRequiredProperty(dsseElement, "key"); var dsse = new DsseProvenance { EnvelopeDigest = GetRequiredString(dsseElement, "envelopeDigest"), PayloadType = GetRequiredString(dsseElement, "payloadType"), Key = new DsseKeyInfo { KeyId = GetRequiredString(keyElement, "keyId"), Issuer = GetOptionalString(keyElement, "issuer"), Algo = GetOptionalString(keyElement, "algo"), }, Chain = ParseChain(dsseElement) }; if (dsseElement.TryGetProperty("rekor", out var rekorElement) && rekorElement.ValueKind == JsonValueKind.Object) { dsse.Rekor = new DsseRekorInfo { LogIndex = GetInt64(rekorElement, "logIndex"), Uuid = GetRequiredString(rekorElement, "uuid"), IntegratedTime = GetOptionalInt64(rekorElement, "integratedTime"), MirrorSeq = GetOptionalInt64(rekorElement, "mirrorSeq") }; } return dsse; } private static IReadOnlyCollection? ParseChain(JsonElement dsseElement) { if (!dsseElement.TryGetProperty("chain", out var chainElement) || chainElement.ValueKind != JsonValueKind.Array || chainElement.GetArrayLength() == 0) { return null; } var links = new List(chainElement.GetArrayLength()); foreach (var entry in chainElement.EnumerateArray()) { if (entry.ValueKind != JsonValueKind.Object) { continue; } var type = GetOptionalString(entry, "type"); var id = GetOptionalString(entry, "id"); var digest = GetOptionalString(entry, "digest"); if (string.IsNullOrEmpty(type) || string.IsNullOrEmpty(id) || string.IsNullOrEmpty(digest)) { continue; } links.Add(new DsseChainLink { Type = type, Id = id, Digest = digest }); } return links.Count == 0 ? null : links; } }