fix: compilation errors in Attestor and Policy modules

- Fix PredicateSchemaValidator to use static Lazy initialization
  avoiding JsonSchema.Net global registry conflicts in tests
- Add IContextPolicyGate interface for gates without MergeResult
- Rename ICveGate/IAttestationGate to avoid conflicts with IPolicyGate
- Add static Pass/Fail helper methods to GateResult record
- Unseal PolicyGateContext to allow ExtendedPolicyGateContext
- Add missing Type/Constraint properties to AuthorityScope and Principal
- Fix PolicyBundle to use ConditionDescription instead of Condition func
- Rename ExceptionResult to ExceptionCheckResult to avoid duplicate
- Rename GateResult static helper class to GateResultFactory
- Temporarily exclude 9 incomplete gate files with missing contracts
- Add AttestationContextExtensions for GetAttestation/GetVexSummary etc

All 216 Attestor.Core tests pass.
This commit is contained in:
master
2026-01-19 13:35:21 +02:00
parent 17419ba7c4
commit b34bde89fa
20 changed files with 280 additions and 73 deletions

View File

@@ -3,7 +3,7 @@ using StellaOps.Policy.TrustLattice;
namespace StellaOps.Policy.Gates;
public sealed record PolicyGateContext
public record PolicyGateContext
{
public string Environment { get; init; } = "production";
public int UnknownCount { get; init; }
@@ -42,6 +42,77 @@ public sealed record GateResult
public required bool Passed { get; init; }
public required string? Reason { get; init; }
public required ImmutableDictionary<string, object> Details { get; init; }
/// <summary>
/// Creates a passing gate result.
/// </summary>
public static GateResult Pass(string gateName, string reason, IEnumerable<string>? warnings = null)
{
var details = ImmutableDictionary<string, object>.Empty;
if (warnings != null)
{
var warningList = warnings.ToList();
if (warningList.Count > 0)
{
details = details.Add("warnings", warningList);
}
}
return new GateResult
{
GateName = gateName,
Passed = true,
Reason = reason,
Details = details
};
}
/// <summary>
/// Creates a passing gate result with child gate results.
/// </summary>
public static GateResult Pass(string gateName, string reason, IReadOnlyList<GateResult>? childResults)
{
var details = childResults != null && childResults.Count > 0
? ImmutableDictionary<string, object>.Empty.Add("childResults", childResults)
: ImmutableDictionary<string, object>.Empty;
return new GateResult
{
GateName = gateName,
Passed = true,
Reason = reason,
Details = details
};
}
/// <summary>
/// Creates a failing gate result.
/// </summary>
public static GateResult Fail(string gateName, string reason, ImmutableDictionary<string, object>? details = null)
{
return new GateResult
{
GateName = gateName,
Passed = false,
Reason = reason,
Details = details ?? ImmutableDictionary<string, object>.Empty
};
}
/// <summary>
/// Creates a failing gate result with child gate results.
/// </summary>
public static GateResult Fail(string gateName, string reason, IReadOnlyList<GateResult>? childResults)
{
var details = childResults != null && childResults.Count > 0
? ImmutableDictionary<string, object>.Empty.Add("childResults", childResults)
: ImmutableDictionary<string, object>.Empty;
return new GateResult
{
GateName = gateName,
Passed = false,
Reason = reason,
Details = details
};
}
}
public sealed record GateEvaluationResult
@@ -51,6 +122,9 @@ public sealed record GateEvaluationResult
public GateResult? FirstFailure => Results.FirstOrDefault(r => !r.Passed);
}
/// <summary>
/// Policy gate interface for gates that require MergeResult.
/// </summary>
public interface IPolicyGate
{
Task<GateResult> EvaluateAsync(
@@ -59,6 +133,33 @@ public interface IPolicyGate
CancellationToken ct = default);
}
/// <summary>
/// Simplified policy gate interface for context-only evaluation.
/// Used by attestation, runtime witness, and CVE gates that don't require MergeResult.
/// </summary>
public interface IContextPolicyGate
{
/// <summary>
/// Gate identifier.
/// </summary>
string Id { get; }
/// <summary>
/// Display name for the gate.
/// </summary>
string DisplayName { get; }
/// <summary>
/// Description of what the gate checks.
/// </summary>
string Description { get; }
/// <summary>
/// Evaluates the gate against the given context.
/// </summary>
Task<GateResult> EvaluateAsync(PolicyGateContext context, CancellationToken ct = default);
}
public sealed record PolicyGateRegistryOptions
{
public bool StopOnFirstFailure { get; init; } = true;