save development progress
This commit is contained in:
@@ -70,6 +70,15 @@ public static partial class ProvcacheEndpointExtensions
|
||||
.Produces<ProvcacheMetricsResponse>(StatusCodes.Status200OK)
|
||||
.Produces<ProblemDetails>(StatusCodes.Status500InternalServerError);
|
||||
|
||||
// GET /v1/provcache/{veriKey}/manifest
|
||||
group.MapGet("/{veriKey}/manifest", GetInputManifest)
|
||||
.WithName("GetInputManifest")
|
||||
.WithSummary("Get input manifest for VeriKey components")
|
||||
.WithDescription("Returns detailed information about the inputs (SBOM, VEX, policy, signers) that formed a cached decision. Use for transparency and debugging.")
|
||||
.Produces<InputManifestResponse>(StatusCodes.Status200OK)
|
||||
.Produces(StatusCodes.Status404NotFound)
|
||||
.Produces<ProblemDetails>(StatusCodes.Status500InternalServerError);
|
||||
|
||||
// Map evidence paging endpoints under /proofs
|
||||
var proofsGroup = endpoints.MapGroup($"{prefix}/proofs")
|
||||
.WithTags("Provcache Evidence")
|
||||
@@ -307,6 +316,119 @@ public static partial class ProvcacheEndpointExtensions
|
||||
title: "Metrics retrieval failed");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// GET /v1/provcache/{veriKey}/manifest
|
||||
/// </summary>
|
||||
private static async Task<IResult> GetInputManifest(
|
||||
string veriKey,
|
||||
IProvcacheService provcacheService,
|
||||
TimeProvider timeProvider,
|
||||
ILogger<ProvcacheApiEndpoints> logger,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
logger.LogDebug("GET /v1/provcache/{VeriKey}/manifest", veriKey);
|
||||
|
||||
try
|
||||
{
|
||||
// First get the entry to verify it exists
|
||||
var result = await provcacheService.GetAsync(veriKey, bypassCache: false, cancellationToken);
|
||||
|
||||
if (result.Status == ProvcacheResultStatus.CacheMiss)
|
||||
{
|
||||
return Results.NotFound(new ProblemDetails
|
||||
{
|
||||
Title = "Entry not found",
|
||||
Detail = $"No cache entry found for VeriKey: {veriKey}",
|
||||
Status = StatusCodes.Status404NotFound
|
||||
});
|
||||
}
|
||||
|
||||
if (result.Status == ProvcacheResultStatus.Expired)
|
||||
{
|
||||
return Results.NotFound(new ProblemDetails
|
||||
{
|
||||
Title = "Entry expired",
|
||||
Detail = $"Cache entry for VeriKey '{veriKey}' has expired",
|
||||
Status = StatusCodes.Status404NotFound
|
||||
});
|
||||
}
|
||||
|
||||
var entry = result.Entry;
|
||||
if (entry is null)
|
||||
{
|
||||
return Results.NotFound(new ProblemDetails
|
||||
{
|
||||
Title = "Entry not found",
|
||||
Detail = $"No cache entry found for VeriKey: {veriKey}",
|
||||
Status = StatusCodes.Status404NotFound
|
||||
});
|
||||
}
|
||||
|
||||
// Build the input manifest from the entry metadata
|
||||
// In a full implementation, we'd resolve these hashes to more detailed metadata
|
||||
// from their respective stores (SBOM store, VEX store, policy registry, etc.)
|
||||
var manifest = BuildInputManifest(entry, timeProvider);
|
||||
|
||||
return Results.Ok(manifest);
|
||||
}
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Builds an InputManifestResponse from a ProvcacheEntry.
|
||||
/// </summary>
|
||||
private static InputManifestResponse BuildInputManifest(ProvcacheEntry entry, TimeProvider timeProvider)
|
||||
{
|
||||
// Build input manifest from the entry and its embedded DecisionDigest
|
||||
// The DecisionDigest contains the VeriKey components as hashes
|
||||
var decision = entry.Decision;
|
||||
|
||||
return new InputManifestResponse
|
||||
{
|
||||
VeriKey = entry.VeriKey,
|
||||
SourceArtifact = new SourceArtifactInfo
|
||||
{
|
||||
// VeriKey includes source hash as first component
|
||||
Digest = entry.VeriKey,
|
||||
},
|
||||
Sbom = new SbomInfoDto
|
||||
{
|
||||
// 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
|
||||
},
|
||||
Vex = new VexInfoDto
|
||||
{
|
||||
// VEX hash set is embedded in VeriKey computation
|
||||
HashSetHash = $"sha256:{entry.VeriKey[7..39]}...", // Placeholder
|
||||
StatementCount = 0, // Would be resolved from VEX store
|
||||
},
|
||||
Policy = new PolicyInfoDto
|
||||
{
|
||||
Hash = entry.PolicyHash,
|
||||
},
|
||||
Signers = new SignerInfoDto
|
||||
{
|
||||
SetHash = entry.SignerSetHash,
|
||||
SignerCount = 0, // Would be resolved from signer registry
|
||||
},
|
||||
TimeWindow = new TimeWindowInfoDto
|
||||
{
|
||||
Bucket = entry.FeedEpoch,
|
||||
StartsAt = entry.CreatedAt,
|
||||
EndsAt = entry.ExpiresAt,
|
||||
},
|
||||
GeneratedAt = timeProvider.GetUtcNow(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
Reference in New Issue
Block a user