Refactor code structure for improved readability and maintainability; optimize performance in key functions.

This commit is contained in:
master
2025-12-22 19:06:31 +02:00
parent dfaa2079aa
commit 4602ccc3a3
1444 changed files with 109919 additions and 8058 deletions

View File

@@ -0,0 +1,142 @@
using System.Collections.Immutable;
using FluentAssertions;
using Microsoft.Extensions.Logging.Abstractions;
using StellaOps.Policy.Exceptions.Models;
using StellaOps.Policy.Exceptions.Services;
using Xunit;
namespace StellaOps.Policy.Exceptions.Tests;
public sealed class EvidenceRequirementValidatorTests
{
[Fact]
public async Task ValidateForApprovalAsync_NoHooks_ReturnsValid()
{
var validator = CreateValidator(new StubHookRegistry([]));
var exception = CreateException();
var result = await validator.ValidateForApprovalAsync(exception);
result.IsValid.Should().BeTrue();
result.MissingEvidence.Should().BeEmpty();
}
[Fact]
public async Task ValidateForApprovalAsync_MissingEvidence_ReturnsInvalid()
{
var hooks = ImmutableArray.Create(new EvidenceHook
{
HookId = "hook-1",
Type = EvidenceType.FeatureFlagDisabled,
Description = "Feature flag disabled",
IsMandatory = true
});
var validator = CreateValidator(new StubHookRegistry(hooks));
var exception = CreateException();
var result = await validator.ValidateForApprovalAsync(exception);
result.IsValid.Should().BeFalse();
result.MissingEvidence.Should().HaveCount(1);
}
[Fact]
public async Task ValidateForApprovalAsync_TrustScoreTooLow_ReturnsInvalid()
{
var hooks = ImmutableArray.Create(new EvidenceHook
{
HookId = "hook-1",
Type = EvidenceType.BackportMerged,
Description = "Backport merged",
IsMandatory = true,
MinTrustScore = 0.8m
});
var validator = CreateValidator(
new StubHookRegistry(hooks),
trustScore: 0.5m);
var exception = CreateException(new EvidenceRequirements
{
Hooks = hooks,
SubmittedEvidence = ImmutableArray.Create(new SubmittedEvidence
{
EvidenceId = "e-1",
HookId = "hook-1",
Type = EvidenceType.BackportMerged,
Reference = "ref",
SubmittedAt = DateTimeOffset.UtcNow,
SubmittedBy = "tester",
ValidationStatus = EvidenceValidationStatus.Valid
})
});
var result = await validator.ValidateForApprovalAsync(exception);
result.IsValid.Should().BeFalse();
result.InvalidEvidence.Should().HaveCount(1);
}
private static EvidenceRequirementValidator CreateValidator(
IEvidenceHookRegistry registry,
decimal trustScore = 1.0m,
bool schemaValid = true,
bool signatureValid = true)
{
return new EvidenceRequirementValidator(
registry,
new StubAttestationVerifier(signatureValid),
new StubTrustScoreService(trustScore),
new StubSchemaValidator(schemaValid),
NullLogger<EvidenceRequirementValidator>.Instance);
}
private static ExceptionObject CreateException(EvidenceRequirements? requirements = null)
{
return new ExceptionObject
{
ExceptionId = "EXC-TEST",
Version = 1,
Status = ExceptionStatus.Active,
Type = ExceptionType.Vulnerability,
Scope = new ExceptionScope { VulnerabilityId = "CVE-2024-0001" },
OwnerId = "owner",
RequesterId = "requester",
CreatedAt = DateTimeOffset.UtcNow,
UpdatedAt = DateTimeOffset.UtcNow,
ExpiresAt = DateTimeOffset.UtcNow.AddDays(30),
ReasonCode = ExceptionReason.AcceptedRisk,
Rationale = "This rationale is long enough to satisfy the minimum character requirement.",
EvidenceRequirements = requirements
};
}
private sealed class StubHookRegistry(ImmutableArray<EvidenceHook> hooks) : IEvidenceHookRegistry
{
public Task<ImmutableArray<EvidenceHook>> GetRequiredHooksAsync(
ExceptionType exceptionType,
ExceptionScope scope,
CancellationToken ct = default) => Task.FromResult(hooks);
}
private sealed class StubAttestationVerifier(bool isValid) : IAttestationVerifier
{
public Task<EvidenceVerificationResult> VerifyAsync(string dsseEnvelope, CancellationToken ct = default) =>
Task.FromResult(new EvidenceVerificationResult(isValid, isValid ? null : "invalid"));
}
private sealed class StubTrustScoreService(decimal score) : ITrustScoreService
{
public Task<decimal> GetScoreAsync(string reference, CancellationToken ct = default) => Task.FromResult(score);
}
private sealed class StubSchemaValidator(bool isValid) : IEvidenceSchemaValidator
{
public Task<EvidenceSchemaValidationResult> ValidateAsync(
string schemaId,
string? content,
CancellationToken ct = default) =>
Task.FromResult(new EvidenceSchemaValidationResult(isValid, isValid ? null : "schema invalid"));
}
}

View File

@@ -0,0 +1,71 @@
using System.Collections.Immutable;
using FluentAssertions;
using StellaOps.Policy.Exceptions.Models;
using Xunit;
namespace StellaOps.Policy.Exceptions.Tests;
public sealed class EvidenceRequirementsTests
{
[Fact]
public void EvidenceRequirements_ShouldBeSatisfied_WhenAllMandatoryHooksValid()
{
var hooks = ImmutableArray.Create(
new EvidenceHook
{
HookId = "hook-1",
Type = EvidenceType.FeatureFlagDisabled,
Description = "Feature flag disabled",
IsMandatory = true
},
new EvidenceHook
{
HookId = "hook-2",
Type = EvidenceType.BackportMerged,
Description = "Backport merged",
IsMandatory = false
});
var submitted = ImmutableArray.Create(new SubmittedEvidence
{
EvidenceId = "e-1",
HookId = "hook-1",
Type = EvidenceType.FeatureFlagDisabled,
Reference = "attestation:feature-flag",
SubmittedAt = DateTimeOffset.UtcNow,
SubmittedBy = "tester",
ValidationStatus = EvidenceValidationStatus.Valid
});
var requirements = new EvidenceRequirements
{
Hooks = hooks,
SubmittedEvidence = submitted
};
requirements.IsSatisfied.Should().BeTrue();
requirements.MissingEvidence.Should().BeEmpty();
}
[Fact]
public void EvidenceRequirements_ShouldReportMissing_WhenMandatoryHookMissing()
{
var hooks = ImmutableArray.Create(new EvidenceHook
{
HookId = "hook-1",
Type = EvidenceType.CompensatingControl,
Description = "Compensating control",
IsMandatory = true
});
var requirements = new EvidenceRequirements
{
Hooks = hooks,
SubmittedEvidence = []
};
requirements.IsSatisfied.Should().BeFalse();
requirements.MissingEvidence.Should().HaveCount(1);
requirements.MissingEvidence[0].HookId.Should().Be("hook-1");
}
}

View File

@@ -210,6 +210,40 @@ public sealed class ExceptionObjectTests
exception.EvidenceRefs.Should().Contain("sha256:evidence1hash");
}
[Fact]
public void ExceptionObject_IsBlockedByRecheck_WhenBlockTriggered_ShouldBeTrue()
{
// Arrange
var exception = CreateException(recheckResult: new RecheckEvaluationResult
{
IsTriggered = true,
TriggeredConditions = [],
RecommendedAction = RecheckAction.Block,
EvaluatedAt = DateTimeOffset.UtcNow
});
// Act & Assert
exception.IsBlockedByRecheck.Should().BeTrue();
exception.RequiresReapproval.Should().BeFalse();
}
[Fact]
public void ExceptionObject_RequiresReapproval_WhenReapprovalTriggered_ShouldBeTrue()
{
// Arrange
var exception = CreateException(recheckResult: new RecheckEvaluationResult
{
IsTriggered = true,
TriggeredConditions = [],
RecommendedAction = RecheckAction.RequireReapproval,
EvaluatedAt = DateTimeOffset.UtcNow
});
// Act & Assert
exception.RequiresReapproval.Should().BeTrue();
exception.IsBlockedByRecheck.Should().BeFalse();
}
[Fact]
public void ExceptionObject_WithMetadata_ShouldStoreKeyValuePairs()
{
@@ -265,7 +299,8 @@ public sealed class ExceptionObjectTests
DateTimeOffset? expiresAt = null,
ImmutableArray<string>? approverIds = null,
ImmutableArray<string>? evidenceRefs = null,
ImmutableDictionary<string, string>? metadata = null)
ImmutableDictionary<string, string>? metadata = null,
RecheckEvaluationResult? recheckResult = null)
{
return new ExceptionObject
{
@@ -287,7 +322,9 @@ public sealed class ExceptionObjectTests
Rationale = "This is a test rationale that meets the minimum character requirement of 50 characters.",
EvidenceRefs = evidenceRefs ?? [],
CompensatingControls = [],
Metadata = metadata ?? ImmutableDictionary<string, string>.Empty
Metadata = metadata ?? ImmutableDictionary<string, string>.Empty,
LastRecheckResult = recheckResult,
LastRecheckAt = recheckResult?.EvaluatedAt
};
}

View File

@@ -0,0 +1,190 @@
using System.Collections.Immutable;
using FluentAssertions;
using StellaOps.Policy.Exceptions.Models;
using StellaOps.Policy.Exceptions.Services;
using Xunit;
namespace StellaOps.Policy.Exceptions.Tests;
public sealed class RecheckEvaluationServiceTests
{
[Fact]
public async Task EvaluateAsync_NoPolicy_ReturnsNoTrigger()
{
var service = new RecheckEvaluationService();
var exception = CreateException(recheckPolicy: null);
var context = new RecheckEvaluationContext
{
ArtifactDigest = "sha256:abc",
Environment = "prod",
EvaluatedAt = DateTimeOffset.UtcNow
};
var result = await service.EvaluateAsync(exception, context);
result.IsTriggered.Should().BeFalse();
result.RecommendedAction.Should().BeNull();
}
[Fact]
public async Task EvaluateAsync_EpssAbove_Triggers()
{
var service = new RecheckEvaluationService();
var policy = new RecheckPolicy
{
PolicyId = "policy-1",
Name = "EPSS gate",
DefaultAction = RecheckAction.Warn,
CreatedAt = DateTimeOffset.UtcNow,
Conditions = ImmutableArray.Create(new RecheckCondition
{
Type = RecheckConditionType.EPSSAbove,
Threshold = 0.5m,
Action = RecheckAction.RequireReapproval
})
};
var exception = CreateException(recheckPolicy: policy);
var context = new RecheckEvaluationContext
{
ArtifactDigest = "sha256:abc",
Environment = "prod",
EvaluatedAt = DateTimeOffset.UtcNow,
EpssScore = 0.9m
};
var result = await service.EvaluateAsync(exception, context);
result.IsTriggered.Should().BeTrue();
result.TriggeredConditions.Should().HaveCount(1);
result.RecommendedAction.Should().Be(RecheckAction.RequireReapproval);
}
[Fact]
public async Task EvaluateAsync_EnvironmentScope_FiltersConditions()
{
var service = new RecheckEvaluationService();
var policy = new RecheckPolicy
{
PolicyId = "policy-1",
Name = "Env gate",
DefaultAction = RecheckAction.Warn,
CreatedAt = DateTimeOffset.UtcNow,
Conditions = ImmutableArray.Create(new RecheckCondition
{
Type = RecheckConditionType.KEVFlagged,
Action = RecheckAction.Block,
EnvironmentScope = ["prod"]
})
};
var exception = CreateException(recheckPolicy: policy);
var context = new RecheckEvaluationContext
{
ArtifactDigest = "sha256:abc",
Environment = "dev",
EvaluatedAt = DateTimeOffset.UtcNow,
KevFlagged = true
};
var result = await service.EvaluateAsync(exception, context);
result.IsTriggered.Should().BeFalse();
}
[Fact]
public async Task EvaluateAsync_ActionPriority_PicksBlock()
{
var service = new RecheckEvaluationService();
var policy = new RecheckPolicy
{
PolicyId = "policy-1",
Name = "Priority gate",
DefaultAction = RecheckAction.Warn,
CreatedAt = DateTimeOffset.UtcNow,
Conditions = ImmutableArray.Create(
new RecheckCondition
{
Type = RecheckConditionType.ExpiryWithin,
Threshold = 10,
Action = RecheckAction.Warn
},
new RecheckCondition
{
Type = RecheckConditionType.KEVFlagged,
Action = RecheckAction.Block
})
};
var exception = CreateException(
expiresAt: DateTimeOffset.UtcNow.AddDays(1),
recheckPolicy: policy);
var context = new RecheckEvaluationContext
{
ArtifactDigest = "sha256:abc",
Environment = "prod",
EvaluatedAt = DateTimeOffset.UtcNow,
KevFlagged = true
};
var result = await service.EvaluateAsync(exception, context);
result.IsTriggered.Should().BeTrue();
result.RecommendedAction.Should().Be(RecheckAction.Block);
}
[Fact]
public async Task EvaluateAsync_ExpiryWithin_UsesThreshold()
{
var service = new RecheckEvaluationService();
var policy = new RecheckPolicy
{
PolicyId = "policy-1",
Name = "Expiry gate",
DefaultAction = RecheckAction.Warn,
CreatedAt = DateTimeOffset.UtcNow,
Conditions = ImmutableArray.Create(new RecheckCondition
{
Type = RecheckConditionType.ExpiryWithin,
Threshold = 5,
Action = RecheckAction.Warn
})
};
var exception = CreateException(
expiresAt: DateTimeOffset.UtcNow.AddDays(3),
recheckPolicy: policy);
var context = new RecheckEvaluationContext
{
ArtifactDigest = "sha256:abc",
Environment = "prod",
EvaluatedAt = DateTimeOffset.UtcNow
};
var result = await service.EvaluateAsync(exception, context);
result.IsTriggered.Should().BeTrue();
}
private static ExceptionObject CreateException(
DateTimeOffset? expiresAt = null,
RecheckPolicy? recheckPolicy = null)
{
return new ExceptionObject
{
ExceptionId = "EXC-TEST",
Version = 1,
Status = ExceptionStatus.Active,
Type = ExceptionType.Vulnerability,
Scope = new ExceptionScope { VulnerabilityId = "CVE-2024-0001" },
OwnerId = "owner",
RequesterId = "requester",
CreatedAt = DateTimeOffset.UtcNow,
UpdatedAt = DateTimeOffset.UtcNow,
ExpiresAt = expiresAt ?? DateTimeOffset.UtcNow.AddDays(30),
ReasonCode = ExceptionReason.AcceptedRisk,
Rationale = "This rationale is long enough to satisfy the minimum character requirement.",
RecheckPolicy = recheckPolicy
};
}
}