audit, advisories and doctors/setup work
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
#pragma warning disable ASPDEPR002 // WithOpenApi is deprecated - will migrate to new OpenAPI approach
|
||||
|
||||
using System.Globalization;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
@@ -166,10 +167,7 @@ public static partial class ProvcacheEndpointExtensions
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "Error getting cache entry for VeriKey {VeriKey}", veriKey);
|
||||
return Results.Problem(
|
||||
detail: ex.Message,
|
||||
statusCode: StatusCodes.Status500InternalServerError,
|
||||
title: "Cache lookup failed");
|
||||
return InternalError("Cache lookup failed");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -214,10 +212,7 @@ public static partial class ProvcacheEndpointExtensions
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "Error storing cache entry for VeriKey {VeriKey}", request.Entry?.VeriKey);
|
||||
return Results.Problem(
|
||||
detail: ex.Message,
|
||||
statusCode: StatusCodes.Status500InternalServerError,
|
||||
title: "Cache write failed");
|
||||
return InternalError("Cache write failed");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -269,10 +264,7 @@ public static partial class ProvcacheEndpointExtensions
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "Error invalidating cache entries");
|
||||
return Results.Problem(
|
||||
detail: ex.Message,
|
||||
statusCode: StatusCodes.Status500InternalServerError,
|
||||
title: "Cache invalidation failed");
|
||||
return InternalError("Cache invalidation failed");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -312,10 +304,7 @@ public static partial class ProvcacheEndpointExtensions
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "Error getting cache metrics");
|
||||
return Results.Problem(
|
||||
detail: ex.Message,
|
||||
statusCode: StatusCodes.Status500InternalServerError,
|
||||
title: "Metrics retrieval failed");
|
||||
return InternalError("Metrics retrieval failed");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -377,10 +366,7 @@ public static partial class ProvcacheEndpointExtensions
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "Error getting input manifest for VeriKey {VeriKey}", veriKey);
|
||||
return Results.Problem(
|
||||
detail: ex.Message,
|
||||
statusCode: StatusCodes.Status500InternalServerError,
|
||||
title: "Manifest retrieval failed");
|
||||
return InternalError("Manifest retrieval failed");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -391,7 +377,7 @@ public static partial class ProvcacheEndpointExtensions
|
||||
{
|
||||
// Build input manifest from the entry and its embedded DecisionDigest
|
||||
// The DecisionDigest contains the VeriKey components as hashes
|
||||
var decision = entry.Decision;
|
||||
var placeholderHash = BuildPlaceholderHash(entry.VeriKey);
|
||||
|
||||
return new InputManifestResponse
|
||||
{
|
||||
@@ -405,12 +391,12 @@ public static partial class ProvcacheEndpointExtensions
|
||||
{
|
||||
// SBOM hash is embedded in VeriKey computation
|
||||
// In a full implementation, we'd resolve this from the SBOM store
|
||||
Hash = $"sha256:{entry.VeriKey[7..39]}...", // Placeholder - actual hash would come from VeriKey decomposition
|
||||
Hash = placeholderHash, // Placeholder - actual hash would come from VeriKey decomposition
|
||||
},
|
||||
Vex = new VexInfoDto
|
||||
{
|
||||
// VEX hash set is embedded in VeriKey computation
|
||||
HashSetHash = $"sha256:{entry.VeriKey[7..39]}...", // Placeholder
|
||||
HashSetHash = placeholderHash, // Placeholder
|
||||
StatementCount = 0, // Would be resolved from VEX store
|
||||
},
|
||||
Policy = new PolicyInfoDto
|
||||
@@ -431,6 +417,43 @@ public static partial class ProvcacheEndpointExtensions
|
||||
GeneratedAt = timeProvider.GetUtcNow(),
|
||||
};
|
||||
}
|
||||
|
||||
private static string BuildPlaceholderHash(string veriKey)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(veriKey))
|
||||
{
|
||||
return "sha256:unknown";
|
||||
}
|
||||
|
||||
var trimmed = veriKey;
|
||||
if (trimmed.StartsWith("sha256:", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
trimmed = trimmed["sha256:".Length..];
|
||||
}
|
||||
|
||||
if (trimmed.Length < 32)
|
||||
{
|
||||
return "sha256:unknown";
|
||||
}
|
||||
|
||||
return $"sha256:{trimmed[..32]}...";
|
||||
}
|
||||
|
||||
private static IResult BadRequest(string detail, string title)
|
||||
{
|
||||
return Results.Problem(
|
||||
detail: detail,
|
||||
statusCode: StatusCodes.Status400BadRequest,
|
||||
title: title);
|
||||
}
|
||||
|
||||
private static IResult InternalError(string title)
|
||||
{
|
||||
return Results.Problem(
|
||||
detail: "An unexpected error occurred while processing the request.",
|
||||
statusCode: StatusCodes.Status500InternalServerError,
|
||||
title: title);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -471,6 +494,16 @@ partial class ProvcacheEndpointExtensions
|
||||
|
||||
try
|
||||
{
|
||||
if (offset is < 0)
|
||||
{
|
||||
return BadRequest("Offset must be zero or greater.", "Invalid pagination");
|
||||
}
|
||||
|
||||
if (limit is <= 0)
|
||||
{
|
||||
return BadRequest("Limit must be greater than zero.", "Invalid pagination");
|
||||
}
|
||||
|
||||
var startIndex = offset ?? 0;
|
||||
var pageSize = Math.Min(limit ?? DefaultPageSize, MaxPageSize);
|
||||
|
||||
@@ -481,10 +514,25 @@ partial class ProvcacheEndpointExtensions
|
||||
return Results.NotFound();
|
||||
}
|
||||
|
||||
if (startIndex >= manifest.TotalChunks)
|
||||
{
|
||||
return Results.Ok(new ProofEvidenceResponse
|
||||
{
|
||||
ProofRoot = proofRoot,
|
||||
TotalChunks = manifest.TotalChunks,
|
||||
TotalSize = manifest.TotalSize,
|
||||
Chunks = [],
|
||||
NextCursor = null,
|
||||
HasMore = false
|
||||
});
|
||||
}
|
||||
|
||||
// Get chunk range
|
||||
var chunks = await chunkRepository.GetChunkRangeAsync(proofRoot, startIndex, pageSize, cancellationToken);
|
||||
|
||||
var chunkResponses = chunks.Select(c => new ProofChunkResponse
|
||||
var chunkResponses = chunks
|
||||
.OrderBy(c => c.ChunkIndex)
|
||||
.Select(c => new ProofChunkResponse
|
||||
{
|
||||
ChunkId = c.ChunkId,
|
||||
Index = c.ChunkIndex,
|
||||
@@ -495,7 +543,9 @@ partial class ProvcacheEndpointExtensions
|
||||
}).ToList();
|
||||
|
||||
var hasMore = startIndex + chunks.Count < manifest.TotalChunks;
|
||||
var nextCursor = hasMore ? (startIndex + pageSize).ToString() : null;
|
||||
var nextCursor = hasMore
|
||||
? (startIndex + pageSize).ToString(CultureInfo.InvariantCulture)
|
||||
: null;
|
||||
|
||||
return Results.Ok(new ProofEvidenceResponse
|
||||
{
|
||||
@@ -510,10 +560,7 @@ partial class ProvcacheEndpointExtensions
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "Error getting evidence chunks for proof root {ProofRoot}", proofRoot);
|
||||
return Results.Problem(
|
||||
detail: ex.Message,
|
||||
statusCode: StatusCodes.Status500InternalServerError,
|
||||
title: "Evidence retrieval failed");
|
||||
return InternalError("Evidence retrieval failed");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -536,7 +583,9 @@ partial class ProvcacheEndpointExtensions
|
||||
return Results.NotFound();
|
||||
}
|
||||
|
||||
var chunkMetadata = manifest.Chunks.Select(c => new ChunkMetadataResponse
|
||||
var chunkMetadata = manifest.Chunks
|
||||
.OrderBy(c => c.Index)
|
||||
.Select(c => new ChunkMetadataResponse
|
||||
{
|
||||
ChunkId = c.ChunkId,
|
||||
Index = c.Index,
|
||||
@@ -557,10 +606,7 @@ partial class ProvcacheEndpointExtensions
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "Error getting manifest for proof root {ProofRoot}", proofRoot);
|
||||
return Results.Problem(
|
||||
detail: ex.Message,
|
||||
statusCode: StatusCodes.Status500InternalServerError,
|
||||
title: "Manifest retrieval failed");
|
||||
return InternalError("Manifest retrieval failed");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -597,10 +643,7 @@ partial class ProvcacheEndpointExtensions
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "Error getting chunk {ChunkIndex} for proof root {ProofRoot}", chunkIndex, proofRoot);
|
||||
return Results.Problem(
|
||||
detail: ex.Message,
|
||||
statusCode: StatusCodes.Status500InternalServerError,
|
||||
title: "Chunk retrieval failed");
|
||||
return InternalError("Chunk retrieval failed");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -624,10 +667,11 @@ partial class ProvcacheEndpointExtensions
|
||||
return Results.NotFound();
|
||||
}
|
||||
|
||||
var orderedChunks = chunks.OrderBy(c => c.ChunkIndex).ToList();
|
||||
var chunkResults = new List<ChunkVerificationResult>();
|
||||
var allValid = true;
|
||||
|
||||
foreach (var chunk in chunks)
|
||||
foreach (var chunk in orderedChunks)
|
||||
{
|
||||
var isValid = chunker.VerifyChunk(chunk);
|
||||
var computedHash = isValid ? chunk.ChunkHash : ComputeChunkHash(chunk.Blob);
|
||||
@@ -647,7 +691,7 @@ partial class ProvcacheEndpointExtensions
|
||||
}
|
||||
|
||||
// Verify Merkle root
|
||||
var chunkHashes = chunks.Select(c => c.ChunkHash).ToList();
|
||||
var chunkHashes = orderedChunks.Select(c => c.ChunkHash).ToList();
|
||||
var computedRoot = chunker.ComputeMerkleRoot(chunkHashes);
|
||||
var rootMatches = string.Equals(computedRoot, proofRoot, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
@@ -662,10 +706,7 @@ partial class ProvcacheEndpointExtensions
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "Error verifying proof root {ProofRoot}", proofRoot);
|
||||
return Results.Problem(
|
||||
detail: ex.Message,
|
||||
statusCode: StatusCodes.Status500InternalServerError,
|
||||
title: "Proof verification failed");
|
||||
return InternalError("Proof verification failed");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user