save development progress

This commit is contained in:
StellaOps Bot
2025-12-25 23:09:58 +02:00
parent d71853ad7e
commit aa70af062e
351 changed files with 37683 additions and 150156 deletions

View File

@@ -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>