up
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Concelier Attestation Tests / attestation-tests (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Concelier Attestation Tests / attestation-tests (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,498 @@
|
||||
using FluentAssertions;
|
||||
using StellaOps.Policy.Scoring;
|
||||
using StellaOps.Policy.Scoring.Engine;
|
||||
using Xunit;
|
||||
|
||||
namespace StellaOps.Policy.Scoring.Tests;
|
||||
|
||||
/// <summary>
|
||||
/// Unit tests for CvssV4Engine per FIRST CVSS v4.0 specification.
|
||||
/// </summary>
|
||||
public sealed class CvssV4EngineTests
|
||||
{
|
||||
private readonly ICvssV4Engine _engine = new CvssV4Engine();
|
||||
|
||||
#region Base Score Tests
|
||||
|
||||
[Fact]
|
||||
public void ComputeScores_MaximumSeverity_ReturnsScore10()
|
||||
{
|
||||
// Arrange - Highest severity: Network/Low/None/None/None/High across all impacts
|
||||
var metrics = CreateHighestSeverityMetrics();
|
||||
|
||||
// Act
|
||||
var scores = _engine.ComputeScores(metrics);
|
||||
|
||||
// Assert
|
||||
scores.BaseScore.Should().Be(10.0);
|
||||
scores.EffectiveScore.Should().Be(10.0);
|
||||
scores.EffectiveScoreType.Should().Be(EffectiveScoreType.Base);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ComputeScores_MinimumSeverity_ReturnsLowScore()
|
||||
{
|
||||
// Arrange - Lowest severity: Physical/High/Present/High/Active/None across all impacts
|
||||
var metrics = CreateLowestSeverityMetrics();
|
||||
|
||||
// Act
|
||||
var scores = _engine.ComputeScores(metrics);
|
||||
|
||||
// Assert
|
||||
scores.BaseScore.Should().BeLessThan(2.0);
|
||||
scores.EffectiveScore.Should().BeLessThan(2.0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ComputeScores_MediumSeverity_ReturnsScoreInRange()
|
||||
{
|
||||
// Arrange - Medium severity combination
|
||||
var metrics = new CvssBaseMetrics
|
||||
{
|
||||
AttackVector = AttackVector.Adjacent,
|
||||
AttackComplexity = AttackComplexity.Low,
|
||||
AttackRequirements = AttackRequirements.None,
|
||||
PrivilegesRequired = PrivilegesRequired.Low,
|
||||
UserInteraction = UserInteraction.Passive,
|
||||
VulnerableSystemConfidentiality = ImpactMetricValue.Low,
|
||||
VulnerableSystemIntegrity = ImpactMetricValue.Low,
|
||||
VulnerableSystemAvailability = ImpactMetricValue.None,
|
||||
SubsequentSystemConfidentiality = ImpactMetricValue.None,
|
||||
SubsequentSystemIntegrity = ImpactMetricValue.None,
|
||||
SubsequentSystemAvailability = ImpactMetricValue.None
|
||||
};
|
||||
|
||||
// Act
|
||||
var scores = _engine.ComputeScores(metrics);
|
||||
|
||||
// Assert
|
||||
scores.BaseScore.Should().BeInRange(4.0, 7.0);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Threat Score Tests
|
||||
|
||||
[Fact]
|
||||
public void ComputeScores_WithAttackedThreat_ReturnsThreatScore()
|
||||
{
|
||||
// Arrange
|
||||
var baseMetrics = CreateHighestSeverityMetrics();
|
||||
var threatMetrics = new CvssThreatMetrics { ExploitMaturity = ExploitMaturity.Attacked };
|
||||
|
||||
// Act
|
||||
var scores = _engine.ComputeScores(baseMetrics, threatMetrics);
|
||||
|
||||
// Assert
|
||||
scores.ThreatScore.Should().NotBeNull();
|
||||
scores.ThreatScore!.Value.Should().Be(10.0); // Attacked = 1.0 multiplier
|
||||
scores.EffectiveScoreType.Should().Be(EffectiveScoreType.Threat);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ComputeScores_WithProofOfConceptThreat_ReducesScore()
|
||||
{
|
||||
// Arrange
|
||||
var baseMetrics = CreateHighestSeverityMetrics();
|
||||
var threatMetrics = new CvssThreatMetrics { ExploitMaturity = ExploitMaturity.ProofOfConcept };
|
||||
|
||||
// Act
|
||||
var scores = _engine.ComputeScores(baseMetrics, threatMetrics);
|
||||
|
||||
// Assert
|
||||
scores.ThreatScore.Should().NotBeNull();
|
||||
scores.ThreatScore!.Value.Should().BeLessThan(10.0); // PoC = 0.94 multiplier
|
||||
scores.ThreatScore.Value.Should().BeGreaterThan(9.0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ComputeScores_WithUnreportedThreat_ReducesScoreMore()
|
||||
{
|
||||
// Arrange
|
||||
var baseMetrics = CreateHighestSeverityMetrics();
|
||||
var threatMetrics = new CvssThreatMetrics { ExploitMaturity = ExploitMaturity.Unreported };
|
||||
|
||||
// Act
|
||||
var scores = _engine.ComputeScores(baseMetrics, threatMetrics);
|
||||
|
||||
// Assert
|
||||
scores.ThreatScore.Should().NotBeNull();
|
||||
scores.ThreatScore!.Value.Should().BeLessThan(9.5); // Unreported = 0.91 multiplier
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ComputeScores_WithNotDefinedThreat_ReturnsOnlyBaseScore()
|
||||
{
|
||||
// Arrange
|
||||
var baseMetrics = CreateHighestSeverityMetrics();
|
||||
var threatMetrics = new CvssThreatMetrics { ExploitMaturity = ExploitMaturity.NotDefined };
|
||||
|
||||
// Act
|
||||
var scores = _engine.ComputeScores(baseMetrics, threatMetrics);
|
||||
|
||||
// Assert
|
||||
scores.ThreatScore.Should().BeNull();
|
||||
scores.EffectiveScoreType.Should().Be(EffectiveScoreType.Base);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Environmental Score Tests
|
||||
|
||||
[Fact]
|
||||
public void ComputeScores_WithHighSecurityRequirements_IncreasesScore()
|
||||
{
|
||||
// Arrange
|
||||
var baseMetrics = CreateMediumSeverityMetrics();
|
||||
var envMetrics = new CvssEnvironmentalMetrics
|
||||
{
|
||||
ConfidentialityRequirement = SecurityRequirement.High,
|
||||
IntegrityRequirement = SecurityRequirement.High,
|
||||
AvailabilityRequirement = SecurityRequirement.High
|
||||
};
|
||||
|
||||
// Act
|
||||
var scoresWithoutEnv = _engine.ComputeScores(baseMetrics);
|
||||
var scoresWithEnv = _engine.ComputeScores(baseMetrics, environmentalMetrics: envMetrics);
|
||||
|
||||
// Assert
|
||||
scoresWithEnv.EnvironmentalScore.Should().NotBeNull();
|
||||
scoresWithEnv.EnvironmentalScore!.Value.Should().BeGreaterThan(scoresWithoutEnv.BaseScore);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ComputeScores_WithLowSecurityRequirements_DecreasesScore()
|
||||
{
|
||||
// Arrange
|
||||
var baseMetrics = CreateMediumSeverityMetrics();
|
||||
var envMetrics = new CvssEnvironmentalMetrics
|
||||
{
|
||||
ConfidentialityRequirement = SecurityRequirement.Low,
|
||||
IntegrityRequirement = SecurityRequirement.Low,
|
||||
AvailabilityRequirement = SecurityRequirement.Low
|
||||
};
|
||||
|
||||
// Act
|
||||
var scoresWithoutEnv = _engine.ComputeScores(baseMetrics);
|
||||
var scoresWithEnv = _engine.ComputeScores(baseMetrics, environmentalMetrics: envMetrics);
|
||||
|
||||
// Assert
|
||||
scoresWithEnv.EnvironmentalScore.Should().NotBeNull();
|
||||
scoresWithEnv.EnvironmentalScore!.Value.Should().BeLessThan(scoresWithoutEnv.BaseScore);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ComputeScores_WithModifiedMetrics_AppliesModifications()
|
||||
{
|
||||
// Arrange - Start with network-based vuln, modify to local
|
||||
var baseMetrics = CreateHighestSeverityMetrics();
|
||||
var envMetrics = new CvssEnvironmentalMetrics
|
||||
{
|
||||
ModifiedAttackVector = ModifiedAttackVector.Local
|
||||
};
|
||||
|
||||
// Act
|
||||
var scoresWithoutEnv = _engine.ComputeScores(baseMetrics);
|
||||
var scoresWithEnv = _engine.ComputeScores(baseMetrics, environmentalMetrics: envMetrics);
|
||||
|
||||
// Assert
|
||||
scoresWithEnv.EnvironmentalScore.Should().NotBeNull();
|
||||
scoresWithEnv.EnvironmentalScore!.Value.Should().BeLessThan(scoresWithoutEnv.BaseScore);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Full Score Tests
|
||||
|
||||
[Fact]
|
||||
public void ComputeScores_WithAllMetrics_ReturnsFullScore()
|
||||
{
|
||||
// Arrange
|
||||
var baseMetrics = CreateHighestSeverityMetrics();
|
||||
var threatMetrics = new CvssThreatMetrics { ExploitMaturity = ExploitMaturity.Attacked };
|
||||
var envMetrics = new CvssEnvironmentalMetrics
|
||||
{
|
||||
ConfidentialityRequirement = SecurityRequirement.High
|
||||
};
|
||||
|
||||
// Act
|
||||
var scores = _engine.ComputeScores(baseMetrics, threatMetrics, envMetrics);
|
||||
|
||||
// Assert
|
||||
scores.FullScore.Should().NotBeNull();
|
||||
scores.EffectiveScoreType.Should().Be(EffectiveScoreType.Full);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Vector String Tests
|
||||
|
||||
[Fact]
|
||||
public void BuildVectorString_BaseOnly_ReturnsCorrectFormat()
|
||||
{
|
||||
// Arrange
|
||||
var metrics = CreateHighestSeverityMetrics();
|
||||
|
||||
// Act
|
||||
var vector = _engine.BuildVectorString(metrics);
|
||||
|
||||
// Assert
|
||||
vector.Should().StartWith("CVSS:4.0/");
|
||||
vector.Should().Contain("AV:N");
|
||||
vector.Should().Contain("AC:L");
|
||||
vector.Should().Contain("AT:N");
|
||||
vector.Should().Contain("PR:N");
|
||||
vector.Should().Contain("UI:N");
|
||||
vector.Should().Contain("VC:H");
|
||||
vector.Should().Contain("VI:H");
|
||||
vector.Should().Contain("VA:H");
|
||||
vector.Should().Contain("SC:H");
|
||||
vector.Should().Contain("SI:H");
|
||||
vector.Should().Contain("SA:H");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BuildVectorString_WithThreat_IncludesThreatMetric()
|
||||
{
|
||||
// Arrange
|
||||
var baseMetrics = CreateHighestSeverityMetrics();
|
||||
var threatMetrics = new CvssThreatMetrics { ExploitMaturity = ExploitMaturity.Attacked };
|
||||
|
||||
// Act
|
||||
var vector = _engine.BuildVectorString(baseMetrics, threatMetrics);
|
||||
|
||||
// Assert
|
||||
vector.Should().Contain("E:A");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ParseVector_ValidVector_ReturnsCorrectMetrics()
|
||||
{
|
||||
// Arrange
|
||||
var vector = "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H";
|
||||
|
||||
// Act
|
||||
var result = _engine.ParseVector(vector);
|
||||
|
||||
// Assert
|
||||
result.BaseMetrics.AttackVector.Should().Be(AttackVector.Network);
|
||||
result.BaseMetrics.AttackComplexity.Should().Be(AttackComplexity.Low);
|
||||
result.BaseMetrics.AttackRequirements.Should().Be(AttackRequirements.None);
|
||||
result.BaseMetrics.PrivilegesRequired.Should().Be(PrivilegesRequired.None);
|
||||
result.BaseMetrics.UserInteraction.Should().Be(UserInteraction.None);
|
||||
result.BaseMetrics.VulnerableSystemConfidentiality.Should().Be(ImpactMetricValue.High);
|
||||
result.BaseMetrics.VulnerableSystemIntegrity.Should().Be(ImpactMetricValue.High);
|
||||
result.BaseMetrics.VulnerableSystemAvailability.Should().Be(ImpactMetricValue.High);
|
||||
result.BaseMetrics.SubsequentSystemConfidentiality.Should().Be(ImpactMetricValue.High);
|
||||
result.BaseMetrics.SubsequentSystemIntegrity.Should().Be(ImpactMetricValue.High);
|
||||
result.BaseMetrics.SubsequentSystemAvailability.Should().Be(ImpactMetricValue.High);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ParseVector_WithThreat_ParsesThreatMetric()
|
||||
{
|
||||
// Arrange
|
||||
var vector = "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H/E:A";
|
||||
|
||||
// Act
|
||||
var result = _engine.ParseVector(vector);
|
||||
|
||||
// Assert
|
||||
result.ThreatMetrics.Should().NotBeNull();
|
||||
result.ThreatMetrics!.ExploitMaturity.Should().Be(ExploitMaturity.Attacked);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ParseVector_InvalidPrefix_ThrowsArgumentException()
|
||||
{
|
||||
// Arrange
|
||||
var vector = "CVSS:3.1/AV:N/AC:L";
|
||||
|
||||
// Act & Assert
|
||||
FluentActions.Invoking(() => _engine.ParseVector(vector))
|
||||
.Should().Throw<ArgumentException>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ParseVector_MissingMetric_ThrowsArgumentException()
|
||||
{
|
||||
// Arrange - Missing AV metric
|
||||
var vector = "CVSS:4.0/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H";
|
||||
|
||||
// Act & Assert
|
||||
FluentActions.Invoking(() => _engine.ParseVector(vector))
|
||||
.Should().Throw<ArgumentException>();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Severity Tests
|
||||
|
||||
[Theory]
|
||||
[InlineData(0.0, CvssSeverity.None)]
|
||||
[InlineData(0.1, CvssSeverity.Low)]
|
||||
[InlineData(3.9, CvssSeverity.Low)]
|
||||
[InlineData(4.0, CvssSeverity.Medium)]
|
||||
[InlineData(6.9, CvssSeverity.Medium)]
|
||||
[InlineData(7.0, CvssSeverity.High)]
|
||||
[InlineData(8.9, CvssSeverity.High)]
|
||||
[InlineData(9.0, CvssSeverity.Critical)]
|
||||
[InlineData(10.0, CvssSeverity.Critical)]
|
||||
public void GetSeverity_DefaultThresholds_ReturnsCorrectSeverity(double score, CvssSeverity expected)
|
||||
{
|
||||
// Act
|
||||
var severity = _engine.GetSeverity(score);
|
||||
|
||||
// Assert
|
||||
severity.Should().Be(expected);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetSeverity_CustomThresholds_UsesCustomValues()
|
||||
{
|
||||
// Arrange
|
||||
var thresholds = new CvssSeverityThresholds
|
||||
{
|
||||
LowMin = 0.1,
|
||||
MediumMin = 5.0, // Higher than default 4.0
|
||||
HighMin = 8.0, // Higher than default 7.0
|
||||
CriticalMin = 9.5 // Higher than default 9.0
|
||||
};
|
||||
|
||||
// Act & Assert
|
||||
_engine.GetSeverity(4.5, thresholds).Should().Be(CvssSeverity.Low);
|
||||
_engine.GetSeverity(7.5, thresholds).Should().Be(CvssSeverity.Medium);
|
||||
_engine.GetSeverity(9.0, thresholds).Should().Be(CvssSeverity.High);
|
||||
_engine.GetSeverity(9.5, thresholds).Should().Be(CvssSeverity.Critical);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Determinism Tests
|
||||
|
||||
[Fact]
|
||||
public void ComputeScores_SameInput_ReturnsSameOutput()
|
||||
{
|
||||
// Arrange
|
||||
var metrics = CreateHighestSeverityMetrics();
|
||||
|
||||
// Act
|
||||
var scores1 = _engine.ComputeScores(metrics);
|
||||
var scores2 = _engine.ComputeScores(metrics);
|
||||
var scores3 = _engine.ComputeScores(metrics);
|
||||
|
||||
// Assert
|
||||
scores1.BaseScore.Should().Be(scores2.BaseScore);
|
||||
scores2.BaseScore.Should().Be(scores3.BaseScore);
|
||||
scores1.EffectiveScore.Should().Be(scores3.EffectiveScore);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BuildVectorString_SameInput_ReturnsSameOutput()
|
||||
{
|
||||
// Arrange
|
||||
var metrics = CreateHighestSeverityMetrics();
|
||||
|
||||
// Act
|
||||
var vector1 = _engine.BuildVectorString(metrics);
|
||||
var vector2 = _engine.BuildVectorString(metrics);
|
||||
|
||||
// Assert
|
||||
vector1.Should().Be(vector2);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Roundtrip_BuildAndParse_PreservesMetrics()
|
||||
{
|
||||
// Arrange
|
||||
var originalMetrics = CreateHighestSeverityMetrics();
|
||||
|
||||
// Act
|
||||
var vector = _engine.BuildVectorString(originalMetrics);
|
||||
var parsed = _engine.ParseVector(vector);
|
||||
|
||||
// Assert
|
||||
parsed.BaseMetrics.AttackVector.Should().Be(originalMetrics.AttackVector);
|
||||
parsed.BaseMetrics.AttackComplexity.Should().Be(originalMetrics.AttackComplexity);
|
||||
parsed.BaseMetrics.AttackRequirements.Should().Be(originalMetrics.AttackRequirements);
|
||||
parsed.BaseMetrics.PrivilegesRequired.Should().Be(originalMetrics.PrivilegesRequired);
|
||||
parsed.BaseMetrics.UserInteraction.Should().Be(originalMetrics.UserInteraction);
|
||||
parsed.BaseMetrics.VulnerableSystemConfidentiality.Should().Be(originalMetrics.VulnerableSystemConfidentiality);
|
||||
parsed.BaseMetrics.VulnerableSystemIntegrity.Should().Be(originalMetrics.VulnerableSystemIntegrity);
|
||||
parsed.BaseMetrics.VulnerableSystemAvailability.Should().Be(originalMetrics.VulnerableSystemAvailability);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region FIRST Sample Vector Tests
|
||||
|
||||
/// <summary>
|
||||
/// Tests using sample vectors from FIRST CVSS v4.0 examples.
|
||||
/// </summary>
|
||||
[Theory]
|
||||
[InlineData("CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H", 10.0)]
|
||||
[InlineData("CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N", 9.4)]
|
||||
[InlineData("CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:L/VI:L/VA:L/SC:N/SI:N/SA:N", 6.8)]
|
||||
public void ComputeScores_FirstSampleVectors_ReturnsExpectedScore(string vector, double expectedScore)
|
||||
{
|
||||
// Arrange
|
||||
var metricSet = _engine.ParseVector(vector);
|
||||
|
||||
// Act
|
||||
var scores = _engine.ComputeScores(metricSet.BaseMetrics);
|
||||
|
||||
// Assert - Allow small tolerance for rounding differences
|
||||
scores.BaseScore.Should().BeApproximately(expectedScore, 0.5);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Helper Methods
|
||||
|
||||
private static CvssBaseMetrics CreateHighestSeverityMetrics() => new()
|
||||
{
|
||||
AttackVector = AttackVector.Network,
|
||||
AttackComplexity = AttackComplexity.Low,
|
||||
AttackRequirements = AttackRequirements.None,
|
||||
PrivilegesRequired = PrivilegesRequired.None,
|
||||
UserInteraction = UserInteraction.None,
|
||||
VulnerableSystemConfidentiality = ImpactMetricValue.High,
|
||||
VulnerableSystemIntegrity = ImpactMetricValue.High,
|
||||
VulnerableSystemAvailability = ImpactMetricValue.High,
|
||||
SubsequentSystemConfidentiality = ImpactMetricValue.High,
|
||||
SubsequentSystemIntegrity = ImpactMetricValue.High,
|
||||
SubsequentSystemAvailability = ImpactMetricValue.High
|
||||
};
|
||||
|
||||
private static CvssBaseMetrics CreateLowestSeverityMetrics() => new()
|
||||
{
|
||||
AttackVector = AttackVector.Physical,
|
||||
AttackComplexity = AttackComplexity.High,
|
||||
AttackRequirements = AttackRequirements.Present,
|
||||
PrivilegesRequired = PrivilegesRequired.High,
|
||||
UserInteraction = UserInteraction.Active,
|
||||
VulnerableSystemConfidentiality = ImpactMetricValue.None,
|
||||
VulnerableSystemIntegrity = ImpactMetricValue.None,
|
||||
VulnerableSystemAvailability = ImpactMetricValue.None,
|
||||
SubsequentSystemConfidentiality = ImpactMetricValue.None,
|
||||
SubsequentSystemIntegrity = ImpactMetricValue.None,
|
||||
SubsequentSystemAvailability = ImpactMetricValue.None
|
||||
};
|
||||
|
||||
private static CvssBaseMetrics CreateMediumSeverityMetrics() => new()
|
||||
{
|
||||
AttackVector = AttackVector.Network,
|
||||
AttackComplexity = AttackComplexity.Low,
|
||||
AttackRequirements = AttackRequirements.None,
|
||||
PrivilegesRequired = PrivilegesRequired.Low,
|
||||
UserInteraction = UserInteraction.None,
|
||||
VulnerableSystemConfidentiality = ImpactMetricValue.Low,
|
||||
VulnerableSystemIntegrity = ImpactMetricValue.Low,
|
||||
VulnerableSystemAvailability = ImpactMetricValue.None,
|
||||
SubsequentSystemConfidentiality = ImpactMetricValue.None,
|
||||
SubsequentSystemIntegrity = ImpactMetricValue.None,
|
||||
SubsequentSystemAvailability = ImpactMetricValue.None
|
||||
};
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<LangVersion>preview</LangVersion>
|
||||
<IsPackable>false</IsPackable>
|
||||
<IsTestProject>true</IsTestProject>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
|
||||
<PackageReference Include="xunit" Version="2.6.2" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.4">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.0">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Moq" Version="4.20.70" />
|
||||
<PackageReference Include="FluentAssertions" Version="6.12.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="../../StellaOps.Policy.Scoring/StellaOps.Policy.Scoring.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
Reference in New Issue
Block a user