Complete Entrypoint Detection Re-Engineering Program (Sprints 0410-0415) and Sprint 3500.0002.0003 (Proof Replay + API)
Entrypoint Detection Program (100% complete): - Sprint 0411: Semantic Entrypoint Engine - all 25 tasks DONE - Sprint 0412: Temporal & Mesh Entrypoint - all 19 tasks DONE - Sprint 0413: Speculative Execution Engine - all 19 tasks DONE - Sprint 0414: Binary Intelligence - all 19 tasks DONE - Sprint 0415: Predictive Risk Scoring - all tasks DONE Key deliverables: - SemanticEntrypoint schema with ApplicationIntent/CapabilityClass - TemporalEntrypointGraph and MeshEntrypointGraph - ShellSymbolicExecutor with PathEnumerator and PathConfidenceScorer - CodeFingerprint index with symbol recovery - RiskScore with multi-dimensional risk assessment Sprint 3500.0002.0003 (Proof Replay + API): - ManifestEndpoints with DSSE content negotiation - Proof bundle endpoints by root hash - IdempotencyMiddleware with RFC 9530 Content-Digest - Rate limiting (100 req/hr per tenant) - OpenAPI documentation updates Tests: 357 EntryTrace tests pass, WebService tests blocked by pre-existing infrastructure issue
This commit is contained in:
@@ -0,0 +1,201 @@
|
||||
// -----------------------------------------------------------------------------
|
||||
// ManifestContracts.cs
|
||||
// Sprint: SPRINT_3500_0002_0003_proof_replay_api
|
||||
// Task: T1 - Scan Manifest Endpoint
|
||||
// Description: Request/response contracts for scan manifest operations
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace StellaOps.Scanner.WebService.Contracts;
|
||||
|
||||
/// <summary>
|
||||
/// Response for GET /scans/{scanId}/manifest endpoint.
|
||||
/// </summary>
|
||||
public sealed record ScanManifestResponse
|
||||
{
|
||||
/// <summary>Unique identifier for this manifest.</summary>
|
||||
[JsonPropertyName("manifestId")]
|
||||
public Guid ManifestId { get; init; }
|
||||
|
||||
/// <summary>Reference to the parent scan.</summary>
|
||||
[JsonPropertyName("scanId")]
|
||||
public Guid ScanId { get; init; }
|
||||
|
||||
/// <summary>SHA-256 hash of the canonical manifest content.</summary>
|
||||
[JsonPropertyName("manifestHash")]
|
||||
public string ManifestHash { get; init; } = string.Empty;
|
||||
|
||||
/// <summary>Hash of the input SBOM.</summary>
|
||||
[JsonPropertyName("sbomHash")]
|
||||
public string SbomHash { get; init; } = string.Empty;
|
||||
|
||||
/// <summary>Hash of the rules snapshot.</summary>
|
||||
[JsonPropertyName("rulesHash")]
|
||||
public string RulesHash { get; init; } = string.Empty;
|
||||
|
||||
/// <summary>Hash of the advisory feed snapshot.</summary>
|
||||
[JsonPropertyName("feedHash")]
|
||||
public string FeedHash { get; init; } = string.Empty;
|
||||
|
||||
/// <summary>Hash of the scoring policy.</summary>
|
||||
[JsonPropertyName("policyHash")]
|
||||
public string PolicyHash { get; init; } = string.Empty;
|
||||
|
||||
/// <summary>When the scan started (UTC ISO-8601).</summary>
|
||||
[JsonPropertyName("scanStartedAt")]
|
||||
public DateTimeOffset ScanStartedAt { get; init; }
|
||||
|
||||
/// <summary>When the scan completed (null if still running).</summary>
|
||||
[JsonPropertyName("scanCompletedAt")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public DateTimeOffset? ScanCompletedAt { get; init; }
|
||||
|
||||
/// <summary>Version of the scanner that created this manifest.</summary>
|
||||
[JsonPropertyName("scannerVersion")]
|
||||
public string ScannerVersion { get; init; } = string.Empty;
|
||||
|
||||
/// <summary>When this manifest was created.</summary>
|
||||
[JsonPropertyName("createdAt")]
|
||||
public DateTimeOffset CreatedAt { get; init; }
|
||||
|
||||
/// <summary>Content-Digest header value (RFC 9530).</summary>
|
||||
[JsonPropertyName("contentDigest")]
|
||||
public string ContentDigest { get; init; } = string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Response for GET /scans/{scanId}/manifest with DSSE envelope (Accept: application/dsse+json).
|
||||
/// </summary>
|
||||
public sealed record SignedScanManifestResponse
|
||||
{
|
||||
/// <summary>The scan manifest.</summary>
|
||||
[JsonPropertyName("manifest")]
|
||||
public ScanManifestResponse Manifest { get; init; } = new();
|
||||
|
||||
/// <summary>SHA-256 hash of the canonical manifest content.</summary>
|
||||
[JsonPropertyName("manifestHash")]
|
||||
public string ManifestHash { get; init; } = string.Empty;
|
||||
|
||||
/// <summary>The DSSE envelope containing the signed manifest.</summary>
|
||||
[JsonPropertyName("envelope")]
|
||||
public DsseEnvelopeDto Envelope { get; init; } = new();
|
||||
|
||||
/// <summary>When the manifest was signed (UTC).</summary>
|
||||
[JsonPropertyName("signedAt")]
|
||||
public DateTimeOffset SignedAt { get; init; }
|
||||
|
||||
/// <summary>Whether the signature is valid.</summary>
|
||||
[JsonPropertyName("signatureValid")]
|
||||
public bool SignatureValid { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Response for GET /scans/{scanId}/proofs/{rootHash} endpoint.
|
||||
/// </summary>
|
||||
public sealed record ProofBundleResponse
|
||||
{
|
||||
/// <summary>Reference to the parent scan.</summary>
|
||||
[JsonPropertyName("scanId")]
|
||||
public Guid ScanId { get; init; }
|
||||
|
||||
/// <summary>Root hash of the proof Merkle tree.</summary>
|
||||
[JsonPropertyName("rootHash")]
|
||||
public string RootHash { get; init; } = string.Empty;
|
||||
|
||||
/// <summary>Type of bundle: standard, extended, or minimal.</summary>
|
||||
[JsonPropertyName("bundleType")]
|
||||
public string BundleType { get; init; } = "standard";
|
||||
|
||||
/// <summary>SHA-256 hash of bundle content.</summary>
|
||||
[JsonPropertyName("bundleHash")]
|
||||
public string BundleHash { get; init; } = string.Empty;
|
||||
|
||||
/// <summary>Hash of the proof ledger.</summary>
|
||||
[JsonPropertyName("ledgerHash")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public string? LedgerHash { get; init; }
|
||||
|
||||
/// <summary>Reference to the scan manifest hash.</summary>
|
||||
[JsonPropertyName("manifestHash")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public string? ManifestHash { get; init; }
|
||||
|
||||
/// <summary>Hash of the SBOM in this bundle.</summary>
|
||||
[JsonPropertyName("sbomHash")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public string? SbomHash { get; init; }
|
||||
|
||||
/// <summary>Hash of the VEX in this bundle.</summary>
|
||||
[JsonPropertyName("vexHash")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public string? VexHash { get; init; }
|
||||
|
||||
/// <summary>Key ID used for signing.</summary>
|
||||
[JsonPropertyName("signatureKeyId")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public string? SignatureKeyId { get; init; }
|
||||
|
||||
/// <summary>Signature algorithm.</summary>
|
||||
[JsonPropertyName("signatureAlgorithm")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public string? SignatureAlgorithm { get; init; }
|
||||
|
||||
/// <summary>When this bundle was created.</summary>
|
||||
[JsonPropertyName("createdAt")]
|
||||
public DateTimeOffset CreatedAt { get; init; }
|
||||
|
||||
/// <summary>Optional expiration time for retention policies.</summary>
|
||||
[JsonPropertyName("expiresAt")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public DateTimeOffset? ExpiresAt { get; init; }
|
||||
|
||||
/// <summary>Whether the DSSE signature is valid.</summary>
|
||||
[JsonPropertyName("signatureValid")]
|
||||
public bool SignatureValid { get; init; }
|
||||
|
||||
/// <summary>Verification error message if failed.</summary>
|
||||
[JsonPropertyName("verificationError")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public string? VerificationError { get; init; }
|
||||
|
||||
/// <summary>Content-Digest header value (RFC 9530).</summary>
|
||||
[JsonPropertyName("contentDigest")]
|
||||
public string ContentDigest { get; init; } = string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// List response for GET /scans/{scanId}/proofs endpoint.
|
||||
/// </summary>
|
||||
public sealed record ProofBundleListResponse
|
||||
{
|
||||
/// <summary>List of proof bundles for this scan.</summary>
|
||||
[JsonPropertyName("items")]
|
||||
public IReadOnlyList<ProofBundleSummary> Items { get; init; } = [];
|
||||
|
||||
/// <summary>Total number of bundles.</summary>
|
||||
[JsonPropertyName("total")]
|
||||
public int Total { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Summary of a proof bundle for list responses.
|
||||
/// </summary>
|
||||
public sealed record ProofBundleSummary
|
||||
{
|
||||
/// <summary>Root hash of the proof Merkle tree.</summary>
|
||||
[JsonPropertyName("rootHash")]
|
||||
public string RootHash { get; init; } = string.Empty;
|
||||
|
||||
/// <summary>Type of bundle: standard, extended, or minimal.</summary>
|
||||
[JsonPropertyName("bundleType")]
|
||||
public string BundleType { get; init; } = "standard";
|
||||
|
||||
/// <summary>SHA-256 hash of bundle content.</summary>
|
||||
[JsonPropertyName("bundleHash")]
|
||||
public string BundleHash { get; init; } = string.Empty;
|
||||
|
||||
/// <summary>When this bundle was created.</summary>
|
||||
[JsonPropertyName("createdAt")]
|
||||
public DateTimeOffset CreatedAt { get; init; }
|
||||
}
|
||||
Reference in New Issue
Block a user