Some checks failed
		
		
	
	Build Test Deploy / build-test (push) Has been cancelled
				
			Build Test Deploy / authority-container (push) Has been cancelled
				
			Build Test Deploy / docs (push) Has been cancelled
				
			Build Test Deploy / deploy (push) Has been cancelled
				
			Docs CI / lint-and-preview (push) Has been cancelled
				
			
		
			
				
	
	
		
			84 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			84 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| using System;
 | |
| using System.Collections.Generic;
 | |
| using System.Linq;
 | |
| using System.Security.Cryptography;
 | |
| using System.Text;
 | |
| using System.Text.Json;
 | |
| using System.Text.Json.Serialization;
 | |
| using System.Threading;
 | |
| using System.Threading.Tasks;
 | |
| using Microsoft.Extensions.Logging;
 | |
| using StellaOps.Vexer.Attestation.Models;
 | |
| using StellaOps.Vexer.Attestation.Signing;
 | |
| using StellaOps.Vexer.Core;
 | |
| 
 | |
| namespace StellaOps.Vexer.Attestation.Dsse;
 | |
| 
 | |
| public sealed class VexDsseBuilder
 | |
| {
 | |
|     private const string PayloadType = "application/vnd.in-toto+json";
 | |
| 
 | |
|     private readonly IVexSigner _signer;
 | |
|     private readonly ILogger<VexDsseBuilder> _logger;
 | |
|     private readonly JsonSerializerOptions _serializerOptions;
 | |
| 
 | |
|     public VexDsseBuilder(IVexSigner signer, ILogger<VexDsseBuilder> logger)
 | |
|     {
 | |
|         _signer = signer ?? throw new ArgumentNullException(nameof(signer));
 | |
|         _logger = logger ?? throw new ArgumentNullException(nameof(logger));
 | |
|         _serializerOptions = new JsonSerializerOptions
 | |
|         {
 | |
|             PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
 | |
|             DefaultIgnoreCondition = JsonIgnoreCondition.Never,
 | |
|             WriteIndented = false,
 | |
|         };
 | |
|         _serializerOptions.Converters.Add(new JsonStringEnumConverter(JsonNamingPolicy.CamelCase));
 | |
|     }
 | |
| 
 | |
|     public async ValueTask<DsseEnvelope> CreateEnvelopeAsync(
 | |
|         VexAttestationRequest request,
 | |
|         IReadOnlyDictionary<string, string>? metadata,
 | |
|         CancellationToken cancellationToken)
 | |
|     {
 | |
|         ArgumentNullException.ThrowIfNull(request);
 | |
| 
 | |
|         var predicate = VexAttestationPredicate.FromRequest(request, metadata);
 | |
|         var subject = new VexInTotoSubject(
 | |
|             request.ExportId,
 | |
|             new Dictionary<string, string>(StringComparer.Ordinal)
 | |
|             {
 | |
|                 { request.Artifact.Algorithm.ToLowerInvariant(), request.Artifact.Digest }
 | |
|             });
 | |
| 
 | |
|         var statement = new VexInTotoStatement(
 | |
|             VexInTotoStatement.InTotoType,
 | |
|             "https://stella-ops.org/attestations/vex-export",
 | |
|             new[] { subject },
 | |
|             predicate);
 | |
| 
 | |
|         var payloadBytes = JsonSerializer.SerializeToUtf8Bytes(statement, _serializerOptions);
 | |
|         var signatureResult = await _signer.SignAsync(payloadBytes, cancellationToken).ConfigureAwait(false);
 | |
| 
 | |
|         var envelope = new DsseEnvelope(
 | |
|             Convert.ToBase64String(payloadBytes),
 | |
|             PayloadType,
 | |
|             new[] { new DsseSignature(signatureResult.Signature, signatureResult.KeyId) });
 | |
| 
 | |
|         _logger.LogDebug("DSSE envelope created for export {ExportId}", request.ExportId);
 | |
|         return envelope;
 | |
|     }
 | |
| 
 | |
|     public static string ComputeEnvelopeDigest(DsseEnvelope envelope)
 | |
|     {
 | |
|         ArgumentNullException.ThrowIfNull(envelope);
 | |
|         var envelopeJson = JsonSerializer.Serialize(envelope, new JsonSerializerOptions
 | |
|         {
 | |
|             PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
 | |
|             DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
 | |
|         });
 | |
|         var bytes = Encoding.UTF8.GetBytes(envelopeJson);
 | |
|         var hash = SHA256.HashData(bytes);
 | |
|         return "sha256:" + Convert.ToHexString(hash).ToLowerInvariant();
 | |
|     }
 | |
| }
 |