Refactor code structure for improved readability and maintainability; optimize performance in key functions.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
// -----------------------------------------------------------------------------
|
||||
// FindingEvidenceContractsTests.cs
|
||||
// Sprint: SPRINT_3800_0001_0001_evidence_api_models
|
||||
// Sprint: SPRINT_4300_0001_0002_findings_evidence_api
|
||||
// Description: Unit tests for JSON serialization of evidence API contracts.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
@@ -27,23 +27,26 @@ public class FindingEvidenceContractsTests
|
||||
{
|
||||
FindingId = "finding-123",
|
||||
Cve = "CVE-2021-44228",
|
||||
Component = new ComponentRef
|
||||
Component = new ComponentInfo
|
||||
{
|
||||
Purl = "pkg:maven/org.apache.logging.log4j/log4j-core@2.14.1",
|
||||
Name = "log4j-core",
|
||||
Version = "2.14.1",
|
||||
Type = "maven"
|
||||
Purl = "pkg:maven/org.apache.logging.log4j/log4j-core@2.14.1",
|
||||
Ecosystem = "maven"
|
||||
},
|
||||
ReachablePath = new[] { "com.example.App.main", "org.apache.log4j.Logger.log" },
|
||||
LastSeen = new DateTimeOffset(2025, 12, 18, 12, 0, 0, TimeSpan.Zero)
|
||||
LastSeen = new DateTimeOffset(2025, 12, 18, 12, 0, 0, TimeSpan.Zero),
|
||||
AttestationRefs = new[] { "dsse:sha256:abc123" },
|
||||
Freshness = new FreshnessInfo { IsStale = false }
|
||||
};
|
||||
|
||||
var json = JsonSerializer.Serialize(response, SerializerOptions);
|
||||
|
||||
Assert.Contains("\"finding_id\":\"finding-123\"", json);
|
||||
Assert.Contains("\"cve\":\"CVE-2021-44228\"", json);
|
||||
Assert.Contains("\"component\":", json);
|
||||
Assert.Contains("\"reachable_path\":", json);
|
||||
Assert.Contains("\"last_seen\":", json);
|
||||
Assert.Contains("\"freshness\":", json);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -53,39 +56,35 @@ public class FindingEvidenceContractsTests
|
||||
{
|
||||
FindingId = "finding-456",
|
||||
Cve = "CVE-2023-12345",
|
||||
Component = new ComponentRef
|
||||
Component = new ComponentInfo
|
||||
{
|
||||
Purl = "pkg:npm/lodash@4.17.20",
|
||||
Name = "lodash",
|
||||
Version = "4.17.20",
|
||||
Type = "npm"
|
||||
Purl = "pkg:npm/lodash@4.17.20",
|
||||
Ecosystem = "npm"
|
||||
},
|
||||
Entrypoint = new EntrypointProof
|
||||
Entrypoint = new EntrypointInfo
|
||||
{
|
||||
Type = "http_handler",
|
||||
Type = "http",
|
||||
Route = "/api/v1/users",
|
||||
Method = "POST",
|
||||
Auth = "required",
|
||||
Fqn = "com.example.UserController.createUser"
|
||||
Auth = "jwt:write"
|
||||
},
|
||||
ScoreExplain = new ScoreExplanationDto
|
||||
Score = new ScoreInfo
|
||||
{
|
||||
Kind = "stellaops_risk_v1",
|
||||
RiskScore = 7.5,
|
||||
RiskScore = 75,
|
||||
Contributions = new[]
|
||||
{
|
||||
new ScoreContributionDto
|
||||
new ScoreContribution
|
||||
{
|
||||
Factor = "cvss_base",
|
||||
Weight = 0.4,
|
||||
RawValue = 9.8,
|
||||
Contribution = 3.92,
|
||||
Explanation = "CVSS v4 base score"
|
||||
Factor = "reachability",
|
||||
Value = 25,
|
||||
Reason = "Reachable from entrypoint"
|
||||
}
|
||||
},
|
||||
LastSeen = DateTimeOffset.UtcNow
|
||||
}
|
||||
},
|
||||
LastSeen = DateTimeOffset.UtcNow
|
||||
LastSeen = DateTimeOffset.UtcNow,
|
||||
Freshness = new FreshnessInfo { IsStale = false }
|
||||
};
|
||||
|
||||
var json = JsonSerializer.Serialize(original, SerializerOptions);
|
||||
@@ -94,178 +93,129 @@ public class FindingEvidenceContractsTests
|
||||
Assert.NotNull(deserialized);
|
||||
Assert.Equal(original.FindingId, deserialized.FindingId);
|
||||
Assert.Equal(original.Cve, deserialized.Cve);
|
||||
Assert.Equal(original.Component?.Purl, deserialized.Component?.Purl);
|
||||
Assert.Equal(original.Component.Purl, deserialized.Component.Purl);
|
||||
Assert.Equal(original.Entrypoint?.Type, deserialized.Entrypoint?.Type);
|
||||
Assert.Equal(original.ScoreExplain?.RiskScore, deserialized.ScoreExplain?.RiskScore);
|
||||
Assert.Equal(original.Score?.RiskScore, deserialized.Score?.RiskScore);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ComponentRef_SerializesAllFields()
|
||||
public void ComponentInfo_SerializesAllFields()
|
||||
{
|
||||
var component = new ComponentRef
|
||||
var component = new ComponentInfo
|
||||
{
|
||||
Purl = "pkg:nuget/Newtonsoft.Json@13.0.1",
|
||||
Name = "Newtonsoft.Json",
|
||||
Version = "13.0.1",
|
||||
Type = "nuget"
|
||||
Purl = "pkg:nuget/Newtonsoft.Json@13.0.1",
|
||||
Ecosystem = "nuget"
|
||||
};
|
||||
|
||||
var json = JsonSerializer.Serialize(component, SerializerOptions);
|
||||
|
||||
Assert.Contains("\"purl\":\"pkg:nuget/Newtonsoft.Json@13.0.1\"", json);
|
||||
Assert.Contains("\"name\":\"Newtonsoft.Json\"", json);
|
||||
Assert.Contains("\"version\":\"13.0.1\"", json);
|
||||
Assert.Contains("\"type\":\"nuget\"", json);
|
||||
Assert.Contains("\"purl\":\"pkg:nuget/Newtonsoft.Json@13.0.1\"", json);
|
||||
Assert.Contains("\"ecosystem\":\"nuget\"", json);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EntrypointProof_SerializesWithLocation()
|
||||
public void EntrypointInfo_SerializesAllFields()
|
||||
{
|
||||
var entrypoint = new EntrypointProof
|
||||
var entrypoint = new EntrypointInfo
|
||||
{
|
||||
Type = "grpc_method",
|
||||
Type = "grpc",
|
||||
Route = "grpc.UserService.GetUser",
|
||||
Auth = "required",
|
||||
Phase = "runtime",
|
||||
Fqn = "com.example.UserServiceImpl.getUser",
|
||||
Location = new SourceLocation
|
||||
{
|
||||
File = "src/main/java/com/example/UserServiceImpl.java",
|
||||
Line = 42,
|
||||
Column = 5
|
||||
}
|
||||
Method = "CALL",
|
||||
Auth = "mtls"
|
||||
};
|
||||
|
||||
var json = JsonSerializer.Serialize(entrypoint, SerializerOptions);
|
||||
|
||||
Assert.Contains("\"type\":\"grpc_method\"", json);
|
||||
Assert.Contains("\"type\":\"grpc\"", json);
|
||||
Assert.Contains("\"route\":\"grpc.UserService.GetUser\"", json);
|
||||
Assert.Contains("\"location\":", json);
|
||||
Assert.Contains("\"file\":\"src/main/java/com/example/UserServiceImpl.java\"", json);
|
||||
Assert.Contains("\"line\":42", json);
|
||||
Assert.Contains("\"method\":\"CALL\"", json);
|
||||
Assert.Contains("\"auth\":\"mtls\"", json);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BoundaryProofDto_SerializesWithControls()
|
||||
public void BoundaryInfo_SerializesWithControls()
|
||||
{
|
||||
var boundary = new BoundaryProofDto
|
||||
var boundary = new BoundaryInfo
|
||||
{
|
||||
Kind = "network",
|
||||
Surface = new SurfaceDescriptor
|
||||
{
|
||||
Type = "api",
|
||||
Protocol = "https",
|
||||
Port = 443
|
||||
},
|
||||
Exposure = new ExposureDescriptor
|
||||
{
|
||||
Level = "public",
|
||||
InternetFacing = true,
|
||||
Zone = "dmz"
|
||||
},
|
||||
Auth = new AuthDescriptor
|
||||
{
|
||||
Required = true,
|
||||
Type = "jwt",
|
||||
Roles = new[] { "admin", "user" }
|
||||
},
|
||||
Controls = new[]
|
||||
{
|
||||
new ControlDescriptor
|
||||
{
|
||||
Type = "waf",
|
||||
Active = true,
|
||||
Config = "OWASP-ModSecurity"
|
||||
}
|
||||
},
|
||||
LastSeen = DateTimeOffset.UtcNow,
|
||||
Confidence = 0.95
|
||||
Surface = "api",
|
||||
Exposure = "internet",
|
||||
Controls = new[] { "waf", "rate_limit" }
|
||||
};
|
||||
|
||||
var json = JsonSerializer.Serialize(boundary, SerializerOptions);
|
||||
|
||||
Assert.Contains("\"kind\":\"network\"", json);
|
||||
Assert.Contains("\"internet_facing\":true", json);
|
||||
Assert.Contains("\"controls\":[", json);
|
||||
Assert.Contains("\"confidence\":0.95", json);
|
||||
Assert.Contains("\"surface\":\"api\"", json);
|
||||
Assert.Contains("\"exposure\":\"internet\"", json);
|
||||
Assert.Contains("\"controls\":[\"waf\",\"rate_limit\"]", json);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void VexEvidenceDto_SerializesCorrectly()
|
||||
public void VexStatusInfo_SerializesCorrectly()
|
||||
{
|
||||
var vex = new VexEvidenceDto
|
||||
var vex = new VexStatusInfo
|
||||
{
|
||||
Status = "not_affected",
|
||||
Justification = "vulnerable_code_not_in_execute_path",
|
||||
Impact = "The vulnerable code path is never executed in our usage",
|
||||
AttestationRef = "dsse:sha256:abc123",
|
||||
IssuedAt = new DateTimeOffset(2025, 12, 1, 0, 0, 0, TimeSpan.Zero),
|
||||
ExpiresAt = new DateTimeOffset(2026, 12, 1, 0, 0, 0, TimeSpan.Zero),
|
||||
Source = "vendor"
|
||||
Timestamp = new DateTimeOffset(2025, 12, 1, 0, 0, 0, TimeSpan.Zero),
|
||||
Issuer = "vendor"
|
||||
};
|
||||
|
||||
var json = JsonSerializer.Serialize(vex, SerializerOptions);
|
||||
|
||||
Assert.Contains("\"status\":\"not_affected\"", json);
|
||||
Assert.Contains("\"justification\":\"vulnerable_code_not_in_execute_path\"", json);
|
||||
Assert.Contains("\"attestation_ref\":\"dsse:sha256:abc123\"", json);
|
||||
Assert.Contains("\"source\":\"vendor\"", json);
|
||||
Assert.Contains("\"issuer\":\"vendor\"", json);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScoreExplanationDto_SerializesContributions()
|
||||
public void ScoreInfo_SerializesContributions()
|
||||
{
|
||||
var explanation = new ScoreExplanationDto
|
||||
var score = new ScoreInfo
|
||||
{
|
||||
Kind = "stellaops_risk_v1",
|
||||
RiskScore = 6.2,
|
||||
RiskScore = 62,
|
||||
Contributions = new[]
|
||||
{
|
||||
new ScoreContributionDto
|
||||
new ScoreContribution
|
||||
{
|
||||
Factor = "cvss_base",
|
||||
Weight = 0.4,
|
||||
RawValue = 9.8,
|
||||
Contribution = 3.92,
|
||||
Explanation = "Critical CVSS base score"
|
||||
Value = 40,
|
||||
Reason = "Critical CVSS base score"
|
||||
},
|
||||
new ScoreContributionDto
|
||||
{
|
||||
Factor = "epss",
|
||||
Weight = 0.2,
|
||||
RawValue = 0.45,
|
||||
Contribution = 0.09,
|
||||
Explanation = "45% probability of exploitation"
|
||||
},
|
||||
new ScoreContributionDto
|
||||
new ScoreContribution
|
||||
{
|
||||
Factor = "reachability",
|
||||
Weight = 0.3,
|
||||
RawValue = 1.0,
|
||||
Contribution = 0.3,
|
||||
Explanation = "Reachable from HTTP entrypoint"
|
||||
},
|
||||
new ScoreContributionDto
|
||||
{
|
||||
Factor = "gate_multiplier",
|
||||
Weight = 1.0,
|
||||
RawValue = 0.5,
|
||||
Contribution = -2.11,
|
||||
Explanation = "Auth gate reduces exposure by 50%"
|
||||
Value = 22,
|
||||
Reason = "Reachable from HTTP entrypoint"
|
||||
}
|
||||
},
|
||||
LastSeen = DateTimeOffset.UtcNow
|
||||
}
|
||||
};
|
||||
|
||||
var json = JsonSerializer.Serialize(explanation, SerializerOptions);
|
||||
var json = JsonSerializer.Serialize(score, SerializerOptions);
|
||||
|
||||
Assert.Contains("\"kind\":\"stellaops_risk_v1\"", json);
|
||||
Assert.Contains("\"risk_score\":6.2", json);
|
||||
Assert.Contains("\"contributions\":[", json);
|
||||
Assert.Contains("\"risk_score\":62", json);
|
||||
Assert.Contains("\"factor\":\"cvss_base\"", json);
|
||||
Assert.Contains("\"factor\":\"epss\"", json);
|
||||
Assert.Contains("\"factor\":\"reachability\"", json);
|
||||
Assert.Contains("\"factor\":\"gate_multiplier\"", json);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FreshnessInfo_SerializesCorrectly()
|
||||
{
|
||||
var freshness = new FreshnessInfo
|
||||
{
|
||||
IsStale = true,
|
||||
ExpiresAt = new DateTimeOffset(2025, 12, 31, 0, 0, 0, TimeSpan.Zero),
|
||||
TtlRemainingHours = 0
|
||||
};
|
||||
|
||||
var json = JsonSerializer.Serialize(freshness, SerializerOptions);
|
||||
|
||||
Assert.Contains("\"is_stale\":true", json);
|
||||
Assert.Contains("\"expires_at\":", json);
|
||||
Assert.Contains("\"ttl_remaining_hours\":0", json);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -275,19 +225,22 @@ public class FindingEvidenceContractsTests
|
||||
{
|
||||
FindingId = "finding-minimal",
|
||||
Cve = "CVE-2025-0001",
|
||||
LastSeen = DateTimeOffset.UtcNow
|
||||
// All optional fields are null
|
||||
Component = new ComponentInfo
|
||||
{
|
||||
Name = "unknown",
|
||||
Version = "unknown"
|
||||
},
|
||||
LastSeen = DateTimeOffset.UtcNow,
|
||||
Freshness = new FreshnessInfo { IsStale = false }
|
||||
};
|
||||
|
||||
var json = JsonSerializer.Serialize(response, SerializerOptions);
|
||||
var deserialized = JsonSerializer.Deserialize<FindingEvidenceResponse>(json, SerializerOptions);
|
||||
|
||||
Assert.NotNull(deserialized);
|
||||
Assert.Null(deserialized.Component);
|
||||
Assert.Null(deserialized.ReachablePath);
|
||||
Assert.Null(deserialized.Entrypoint);
|
||||
Assert.Null(deserialized.Boundary);
|
||||
Assert.Null(deserialized.Vex);
|
||||
Assert.Null(deserialized.ScoreExplain);
|
||||
Assert.Null(deserialized.Score);
|
||||
Assert.Null(deserialized.Boundary);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user