409 lines
10 KiB
Markdown
409 lines
10 KiB
Markdown
# Evidence API Reference
|
|
|
|
This document provides the complete API reference for the StellaOps unified evidence model.
|
|
|
|
## Interfaces
|
|
|
|
### IEvidence
|
|
|
|
Base interface for all evidence records.
|
|
|
|
```csharp
|
|
namespace StellaOps.Evidence.Core;
|
|
|
|
public interface IEvidence
|
|
{
|
|
/// <summary>
|
|
/// Content-addressed evidence identifier (e.g., "sha256:abc123...").
|
|
/// </summary>
|
|
string EvidenceId { get; }
|
|
|
|
/// <summary>
|
|
/// The type of evidence this record represents.
|
|
/// </summary>
|
|
EvidenceType Type { get; }
|
|
|
|
/// <summary>
|
|
/// The subject (node ID) this evidence is about.
|
|
/// </summary>
|
|
string SubjectNodeId { get; }
|
|
|
|
/// <summary>
|
|
/// When the evidence was created (UTC).
|
|
/// </summary>
|
|
DateTimeOffset CreatedAt { get; }
|
|
|
|
/// <summary>
|
|
/// Cryptographic signatures attesting to this evidence.
|
|
/// </summary>
|
|
IReadOnlyList<EvidenceSignature> Signatures { get; }
|
|
|
|
/// <summary>
|
|
/// Origin and provenance information.
|
|
/// </summary>
|
|
EvidenceProvenance? Provenance { get; }
|
|
|
|
/// <summary>
|
|
/// Type-specific properties as key-value pairs.
|
|
/// </summary>
|
|
IReadOnlyDictionary<string, string> Properties { get; }
|
|
}
|
|
```
|
|
|
|
### IEvidenceStore
|
|
|
|
Storage interface for evidence persistence.
|
|
|
|
```csharp
|
|
namespace StellaOps.Evidence.Core;
|
|
|
|
public interface IEvidenceStore
|
|
{
|
|
/// <summary>
|
|
/// Retrieves evidence by its content-addressed ID.
|
|
/// </summary>
|
|
Task<IEvidence?> GetAsync(string evidenceId, CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// Retrieves all evidence records for a given subject.
|
|
/// </summary>
|
|
Task<IReadOnlyList<IEvidence>> GetBySubjectAsync(
|
|
string subjectNodeId,
|
|
CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// Retrieves all evidence records of a specific type.
|
|
/// </summary>
|
|
Task<IReadOnlyList<IEvidence>> GetByTypeAsync(
|
|
EvidenceType type,
|
|
CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// Stores an evidence record.
|
|
/// </summary>
|
|
Task StoreAsync(IEvidence evidence, CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// Checks if evidence with the given ID exists.
|
|
/// </summary>
|
|
Task<bool> ExistsAsync(string evidenceId, CancellationToken ct = default);
|
|
}
|
|
```
|
|
|
|
### IEvidenceAdapter<TInput>
|
|
|
|
Adapter interface for converting module-specific types to evidence.
|
|
|
|
```csharp
|
|
namespace StellaOps.Evidence.Core.Adapters;
|
|
|
|
public interface IEvidenceAdapter<TInput>
|
|
{
|
|
/// <summary>
|
|
/// Converts a module-specific input to one or more evidence records.
|
|
/// </summary>
|
|
IReadOnlyList<IEvidence> ToEvidence(TInput input);
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Records
|
|
|
|
### EvidenceRecord
|
|
|
|
Standard implementation of IEvidence.
|
|
|
|
```csharp
|
|
namespace StellaOps.Evidence.Core;
|
|
|
|
public sealed record EvidenceRecord : IEvidence
|
|
{
|
|
public required string EvidenceId { get; init; }
|
|
public required EvidenceType Type { get; init; }
|
|
public required string SubjectNodeId { get; init; }
|
|
public required DateTimeOffset CreatedAt { get; init; }
|
|
public IReadOnlyList<EvidenceSignature> Signatures { get; init; } = [];
|
|
public EvidenceProvenance? Provenance { get; init; }
|
|
public IReadOnlyDictionary<string, string> Properties { get; init; } =
|
|
new Dictionary<string, string>();
|
|
}
|
|
```
|
|
|
|
### EvidenceSignature
|
|
|
|
Cryptographic signature attached to evidence.
|
|
|
|
```csharp
|
|
namespace StellaOps.Evidence.Core;
|
|
|
|
public sealed record EvidenceSignature
|
|
{
|
|
/// <summary>
|
|
/// Identifier of the signer (key ID, tool name, etc.).
|
|
/// </summary>
|
|
public required string SignerId { get; init; }
|
|
|
|
/// <summary>
|
|
/// Signing algorithm (e.g., "Ed25519", "ES256").
|
|
/// </summary>
|
|
public required string Algorithm { get; init; }
|
|
|
|
/// <summary>
|
|
/// Base64-encoded signature bytes.
|
|
/// </summary>
|
|
public required string SignatureBase64 { get; init; }
|
|
|
|
/// <summary>
|
|
/// When the signature was created (UTC).
|
|
/// </summary>
|
|
public required DateTimeOffset SignedAt { get; init; }
|
|
|
|
/// <summary>
|
|
/// Type of entity that produced the signature.
|
|
/// </summary>
|
|
public required SignerType SignerType { get; init; }
|
|
}
|
|
```
|
|
|
|
### EvidenceProvenance
|
|
|
|
Origin and provenance information.
|
|
|
|
```csharp
|
|
namespace StellaOps.Evidence.Core;
|
|
|
|
public sealed record EvidenceProvenance
|
|
{
|
|
/// <summary>
|
|
/// Source that produced this evidence (e.g., "grype", "trivy").
|
|
/// </summary>
|
|
public required string Source { get; init; }
|
|
|
|
/// <summary>
|
|
/// Version of the source tool.
|
|
/// </summary>
|
|
public string? SourceVersion { get; init; }
|
|
|
|
/// <summary>
|
|
/// URI where original data was obtained.
|
|
/// </summary>
|
|
public string? SourceUri { get; init; }
|
|
|
|
/// <summary>
|
|
/// Digest of the original content.
|
|
/// </summary>
|
|
public string? ContentDigest { get; init; }
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Enumerations
|
|
|
|
### EvidenceType
|
|
|
|
```csharp
|
|
namespace StellaOps.Evidence.Core;
|
|
|
|
public enum EvidenceType
|
|
{
|
|
Unknown = 0,
|
|
Sbom = 1,
|
|
Vulnerability = 2,
|
|
Vex = 3,
|
|
Attestation = 4,
|
|
PolicyDecision = 5,
|
|
ScanResult = 6,
|
|
Provenance = 7,
|
|
Signature = 8,
|
|
ProofSegment = 9,
|
|
Exception = 10,
|
|
Advisory = 11,
|
|
CveMatch = 12,
|
|
ReachabilityResult = 13
|
|
}
|
|
```
|
|
|
|
### SignerType
|
|
|
|
```csharp
|
|
namespace StellaOps.Evidence.Core;
|
|
|
|
public enum SignerType
|
|
{
|
|
Unknown = 0,
|
|
Tool = 1,
|
|
Human = 2,
|
|
Authority = 3,
|
|
Vendor = 4,
|
|
Service = 5
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Adapters
|
|
|
|
### EvidenceStatementAdapter
|
|
|
|
Converts `EvidenceStatement` from Attestor module.
|
|
|
|
**Input**: `EvidenceStatementInput`
|
|
|
|
```csharp
|
|
public sealed record EvidenceStatementInput
|
|
{
|
|
public required string StatementId { get; init; }
|
|
public required string SubjectDigest { get; init; }
|
|
public required string StatementType { get; init; }
|
|
public required string PredicateType { get; init; }
|
|
public required DateTimeOffset IssuedAt { get; init; }
|
|
public IReadOnlyList<EvidenceSignatureInput>? Signatures { get; init; }
|
|
public IReadOnlyDictionary<string, string>? Metadata { get; init; }
|
|
}
|
|
```
|
|
|
|
**Output**: Single `IEvidence` record with `Type = Attestation`.
|
|
|
|
---
|
|
|
|
### ProofSegmentAdapter
|
|
|
|
Converts `ProofSegment` from Scanner module.
|
|
|
|
**Input**: `ProofSegmentInput`
|
|
|
|
```csharp
|
|
public sealed record ProofSegmentInput
|
|
{
|
|
public required string SegmentId { get; init; }
|
|
public required string SubjectNodeId { get; init; }
|
|
public required string SegmentType { get; init; }
|
|
public required string Status { get; init; }
|
|
public required DateTimeOffset CreatedAt { get; init; }
|
|
public string? PreviousSegmentId { get; init; }
|
|
public string? PayloadDigest { get; init; }
|
|
public IReadOnlyList<EvidenceSignatureInput>? Signatures { get; init; }
|
|
public IReadOnlyDictionary<string, string>? Properties { get; init; }
|
|
}
|
|
```
|
|
|
|
**Output**: Single `IEvidence` record with `Type = ProofSegment`.
|
|
|
|
---
|
|
|
|
### VexObservationAdapter
|
|
|
|
Converts `VexObservation` from Excititor module.
|
|
|
|
**Input**: `VexObservationInput`
|
|
|
|
```csharp
|
|
public sealed record VexObservationInput
|
|
{
|
|
public required string SubjectDigest { get; init; }
|
|
public VexObservationUpstreamInput? Upstream { get; init; }
|
|
public IReadOnlyList<VexObservationStatementInput>? Statements { get; init; }
|
|
public IReadOnlyDictionary<string, string>? Properties { get; init; }
|
|
}
|
|
|
|
public sealed record VexObservationUpstreamInput
|
|
{
|
|
public required string VexDocumentId { get; init; }
|
|
public required string VendorName { get; init; }
|
|
public required DateTimeOffset PublishedAt { get; init; }
|
|
public string? DocumentDigest { get; init; }
|
|
}
|
|
|
|
public sealed record VexObservationStatementInput
|
|
{
|
|
public required string VulnerabilityId { get; init; }
|
|
public required string ProductId { get; init; }
|
|
public required string Status { get; init; }
|
|
public required DateTimeOffset Timestamp { get; init; }
|
|
public string? Justification { get; init; }
|
|
}
|
|
```
|
|
|
|
**Output**: Multiple `IEvidence` records:
|
|
- 1 record with `Type = Provenance` (from upstream)
|
|
- N records with `Type = Vex` (one per statement)
|
|
|
|
---
|
|
|
|
### ExceptionApplicationAdapter
|
|
|
|
Converts `ExceptionApplication` from Policy module.
|
|
|
|
**Input**: `ExceptionApplicationInput`
|
|
|
|
```csharp
|
|
public sealed record ExceptionApplicationInput
|
|
{
|
|
public required string ApplicationId { get; init; }
|
|
public required string TenantId { get; init; }
|
|
public required string ExceptionId { get; init; }
|
|
public required string FindingId { get; init; }
|
|
public required DateTimeOffset AppliedAt { get; init; }
|
|
public DateTimeOffset? ExpiresAt { get; init; }
|
|
public string? Reason { get; init; }
|
|
public string? AppliedBy { get; init; }
|
|
public IReadOnlyDictionary<string, string>? Properties { get; init; }
|
|
}
|
|
```
|
|
|
|
**Output**: Single `IEvidence` record with `Type = Exception`.
|
|
|
|
---
|
|
|
|
## Implementations
|
|
|
|
### InMemoryEvidenceStore
|
|
|
|
Thread-safe in-memory evidence store for testing and caching.
|
|
|
|
```csharp
|
|
var store = new InMemoryEvidenceStore();
|
|
|
|
// Store evidence
|
|
await store.StoreAsync(record);
|
|
|
|
// Retrieve by ID
|
|
var evidence = await store.GetAsync("sha256:abc123...");
|
|
|
|
// Query by subject
|
|
var subjectEvidence = await store.GetBySubjectAsync("pkg:npm/lodash@4.17.21");
|
|
|
|
// Query by type
|
|
var vexRecords = await store.GetByTypeAsync(EvidenceType.Vex);
|
|
|
|
// Check existence
|
|
var exists = await store.ExistsAsync("sha256:abc123...");
|
|
```
|
|
|
|
**Thread Safety**: Uses `ConcurrentDictionary` for all operations.
|
|
|
|
---
|
|
|
|
## Common Property Keys
|
|
|
|
Standard property keys used across evidence types:
|
|
|
|
| Key | Used By | Description |
|
|
|-----|---------|-------------|
|
|
| `cve` | Vulnerability, CveMatch | CVE identifier |
|
|
| `severity` | Vulnerability | Severity level (CRITICAL, HIGH, etc.) |
|
|
| `cvss` | Vulnerability | CVSS score |
|
|
| `status` | Vex, ProofSegment | Current status |
|
|
| `justification` | Vex, Exception | Reason for status |
|
|
| `productId` | Vex | Affected product identifier |
|
|
| `exceptionId` | Exception | Parent exception ID |
|
|
| `findingId` | Exception | Finding being excepted |
|
|
| `tenantId` | Exception | Tenant context |
|
|
| `segmentType` | ProofSegment | Type of proof segment |
|
|
| `previousSegmentId` | ProofSegment | Chain link to previous segment |
|
|
| `payloadDigest` | ProofSegment | Content digest |
|
|
| `predicateType` | Attestation | In-toto predicate type URI |
|
|
| `statementType` | Attestation | Statement type identifier |
|