new advisories work and features gaps work

This commit is contained in:
master
2026-01-14 18:39:19 +02:00
parent 95d5898650
commit 15aeac8e8b
148 changed files with 16731 additions and 554 deletions

View File

@@ -44,7 +44,17 @@ public sealed record RekorEntryRefDto(
long? LogIndex = null,
string? LogId = null,
string? Uuid = null,
long? IntegratedTime = null);
long? IntegratedTime = null,
/// <summary>
/// Rekor integrated time as RFC3339 timestamp (ISO 8601 format).
/// Sprint: SPRINT_20260112_004_FINDINGS_evidence_graph_rekor_time (FIND-REKOR-002)
/// </summary>
DateTimeOffset? IntegratedTimeRfc3339 = null,
/// <summary>
/// Full URL to the Rekor entry for UI linking.
/// Sprint: SPRINT_20260112_004_FINDINGS_evidence_graph_rekor_time (FIND-REKOR-002)
/// </summary>
string? EntryUrl = null);
/// <summary>
/// Result of attestation verification.
@@ -183,11 +193,14 @@ public static class AttestationPointerMappings
public static RekorEntryRef ToModel(this RekorEntryRefDto dto)
{
// Sprint: SPRINT_20260112_004_FINDINGS_evidence_graph_rekor_time (FIND-REKOR-002)
return new RekorEntryRef(
dto.LogIndex,
dto.LogId,
dto.Uuid,
dto.IntegratedTime);
dto.IntegratedTime,
dto.IntegratedTimeRfc3339,
dto.EntryUrl);
}
public static VerificationResult ToModel(this VerificationResultDto dto)
@@ -253,11 +266,14 @@ public static class AttestationPointerMappings
public static RekorEntryRefDto ToDto(this RekorEntryRef model)
{
// Sprint: SPRINT_20260112_004_FINDINGS_evidence_graph_rekor_time (FIND-REKOR-002)
return new RekorEntryRefDto(
model.LogIndex,
model.LogId,
model.Uuid,
model.IntegratedTime);
model.IntegratedTime,
model.IntegratedTimeRfc3339,
model.EntryUrl);
}
public static VerificationResultDto ToDto(this VerificationResult model)

View File

@@ -155,6 +155,126 @@ public sealed record EvidenceWeightedScoreResponse
/// Whether this result came from cache.
/// </summary>
public bool FromCache { get; init; }
// Sprint: SPRINT_20260112_004_BE_findings_scoring_attested_reduction (EWS-API-001)
/// <summary>
/// Reduction profile metadata when attested reduction is active.
/// </summary>
public ReductionProfileDto? ReductionProfile { get; init; }
/// <summary>
/// Whether this finding has a hard-fail status (must be addressed).
/// </summary>
public bool HardFail { get; init; }
/// <summary>
/// Reason for short-circuit if score was set to 0 due to attested evidence.
/// </summary>
public string? ShortCircuitReason { get; init; }
/// <summary>
/// Anchor metadata for the evidence used in scoring.
/// </summary>
public EvidenceAnchorDto? Anchor { get; init; }
}
/// <summary>
/// Reduction profile metadata for attested scoring.
/// Sprint: SPRINT_20260112_004_BE_findings_scoring_attested_reduction (EWS-API-001)
/// </summary>
public sealed record ReductionProfileDto
{
/// <summary>
/// Whether reduction mode is enabled.
/// </summary>
[JsonPropertyName("enabled")]
public required bool Enabled { get; init; }
/// <summary>
/// Reduction mode (e.g., "aggressive", "conservative", "custom").
/// </summary>
[JsonPropertyName("mode")]
public string? Mode { get; init; }
/// <summary>
/// Policy profile ID used.
/// </summary>
[JsonPropertyName("profileId")]
public string? ProfileId { get; init; }
/// <summary>
/// Maximum reduction percentage allowed.
/// </summary>
[JsonPropertyName("maxReductionPercent")]
public int? MaxReductionPercent { get; init; }
/// <summary>
/// Whether VEX anchoring is required.
/// </summary>
[JsonPropertyName("requireVexAnchoring")]
public bool RequireVexAnchoring { get; init; }
/// <summary>
/// Whether Rekor verification is required.
/// </summary>
[JsonPropertyName("requireRekorVerification")]
public bool RequireRekorVerification { get; init; }
}
/// <summary>
/// Evidence anchor metadata for attested scoring.
/// Sprint: SPRINT_20260112_004_BE_findings_scoring_attested_reduction (EWS-API-001)
/// </summary>
public sealed record EvidenceAnchorDto
{
/// <summary>
/// Whether the evidence is anchored (has attestation).
/// </summary>
[JsonPropertyName("anchored")]
public required bool Anchored { get; init; }
/// <summary>
/// DSSE envelope digest if anchored.
/// </summary>
[JsonPropertyName("envelopeDigest")]
public string? EnvelopeDigest { get; init; }
/// <summary>
/// Predicate type of the attestation.
/// </summary>
[JsonPropertyName("predicateType")]
public string? PredicateType { get; init; }
/// <summary>
/// Rekor log index if transparency-anchored.
/// </summary>
[JsonPropertyName("rekorLogIndex")]
public long? RekorLogIndex { get; init; }
/// <summary>
/// Rekor entry ID if transparency-anchored.
/// </summary>
[JsonPropertyName("rekorEntryId")]
public string? RekorEntryId { get; init; }
/// <summary>
/// Scope of the attestation.
/// </summary>
[JsonPropertyName("scope")]
public string? Scope { get; init; }
/// <summary>
/// Verification status of the anchor.
/// </summary>
[JsonPropertyName("verified")]
public bool? Verified { get; init; }
/// <summary>
/// When the attestation was created.
/// </summary>
[JsonPropertyName("attestedAt")]
public DateTimeOffset? AttestedAt { get; init; }
}
/// <summary>

View File

@@ -73,7 +73,50 @@ public sealed record RekorEntryRef(
long? LogIndex = null,
string? LogId = null,
string? Uuid = null,
long? IntegratedTime = null);
long? IntegratedTime = null,
/// <summary>
/// Rekor integrated time as RFC3339 timestamp (ISO 8601 format).
/// Sprint: SPRINT_20260112_004_FINDINGS_evidence_graph_rekor_time (FIND-REKOR-001)
/// </summary>
DateTimeOffset? IntegratedTimeRfc3339 = null,
/// <summary>
/// Full URL to the Rekor entry for UI linking.
/// Sprint: SPRINT_20260112_004_FINDINGS_evidence_graph_rekor_time (FIND-REKOR-001)
/// </summary>
string? EntryUrl = null)
{
/// <summary>
/// Gets the integrated time as DateTimeOffset.
/// Prioritizes IntegratedTimeRfc3339 if set, otherwise converts IntegratedTime from Unix epoch.
/// </summary>
public DateTimeOffset? GetIntegratedTimeAsDateTime()
{
if (IntegratedTimeRfc3339.HasValue)
return IntegratedTimeRfc3339;
if (IntegratedTime.HasValue)
return DateTimeOffset.FromUnixTimeSeconds(IntegratedTime.Value);
return null;
}
/// <summary>
/// Gets the Rekor entry URL, constructing from UUID if not explicitly set.
/// </summary>
public string? GetEntryUrl(string rekorBaseUrl = "https://rekor.sigstore.dev")
{
if (!string.IsNullOrEmpty(EntryUrl))
return EntryUrl;
if (!string.IsNullOrEmpty(Uuid))
return $"{rekorBaseUrl}/api/v1/log/entries/{Uuid}";
if (!string.IsNullOrEmpty(LogId) && LogIndex.HasValue)
return $"{rekorBaseUrl}/api/v1/log/entries?logIndex={LogIndex.Value}";
return null;
}
};
/// <summary>
/// Result of attestation verification.