Extend Vexer attestation/export stack and Concelier OSV fixes
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
using System.Net.Http.Json;
|
||||
using System.Text.Json;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using StellaOps.Vexer.Attestation.Dsse;
|
||||
|
||||
namespace StellaOps.Vexer.Attestation.Transparency;
|
||||
|
||||
internal sealed class RekorHttpClient : ITransparencyLogClient
|
||||
{
|
||||
private readonly HttpClient _httpClient;
|
||||
private readonly RekorHttpClientOptions _options;
|
||||
private readonly ILogger<RekorHttpClient> _logger;
|
||||
|
||||
public RekorHttpClient(HttpClient httpClient, IOptions<RekorHttpClientOptions> options, ILogger<RekorHttpClient> logger)
|
||||
{
|
||||
_httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient));
|
||||
ArgumentNullException.ThrowIfNull(options);
|
||||
_options = options.Value;
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(_options.BaseAddress))
|
||||
{
|
||||
_httpClient.BaseAddress = new Uri(_options.BaseAddress, UriKind.Absolute);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(_options.ApiKey))
|
||||
{
|
||||
_httpClient.DefaultRequestHeaders.Add("Authorization", _options.ApiKey);
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask<TransparencyLogEntry> SubmitAsync(DsseEnvelope envelope, CancellationToken cancellationToken)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(envelope);
|
||||
var payload = JsonSerializer.Serialize(envelope);
|
||||
using var content = new StringContent(payload);
|
||||
content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");
|
||||
|
||||
HttpResponseMessage? response = null;
|
||||
for (var attempt = 0; attempt < _options.RetryCount; attempt++)
|
||||
{
|
||||
response = await _httpClient.PostAsync("/api/v2/log/entries", content, cancellationToken).ConfigureAwait(false);
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
_logger.LogWarning("Rekor submission failed with status {Status}; attempt {Attempt}", response.StatusCode, attempt + 1);
|
||||
if (attempt + 1 < _options.RetryCount)
|
||||
{
|
||||
await Task.Delay(_options.RetryDelay, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (response is null || !response.IsSuccessStatusCode)
|
||||
{
|
||||
throw new HttpRequestException($"Failed to submit attestation to Rekor ({response?.StatusCode}).");
|
||||
}
|
||||
|
||||
var entryLocation = response.Headers.Location?.ToString() ?? string.Empty;
|
||||
var body = await response.Content.ReadFromJsonAsync<JsonElement>(cancellationToken: cancellationToken).ConfigureAwait(false);
|
||||
var entry = ParseEntryLocation(entryLocation, body);
|
||||
_logger.LogInformation("Rekor entry recorded at {Location}", entry.Location);
|
||||
return entry;
|
||||
}
|
||||
|
||||
public async ValueTask<bool> VerifyAsync(string entryLocation, CancellationToken cancellationToken)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(entryLocation))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var response = await _httpClient.GetAsync(entryLocation, cancellationToken).ConfigureAwait(false);
|
||||
return response.IsSuccessStatusCode;
|
||||
}
|
||||
|
||||
private static TransparencyLogEntry ParseEntryLocation(string location, JsonElement body)
|
||||
{
|
||||
var id = body.TryGetProperty("uuid", out var uuid) ? uuid.GetString() ?? string.Empty : Guid.NewGuid().ToString();
|
||||
var logIndex = body.TryGetProperty("logIndex", out var logIndexElement) ? logIndexElement.GetString() : null;
|
||||
string? inclusionProof = null;
|
||||
if (body.TryGetProperty("verification", out var verification) && verification.TryGetProperty("inclusionProof", out var inclusion))
|
||||
{
|
||||
inclusionProof = inclusion.GetProperty("logIndex").GetRawText();
|
||||
}
|
||||
|
||||
return new TransparencyLogEntry(id, location, logIndex, inclusionProof);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user