Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
Export Center CI / export-ci (push) Has been cancelled
Findings Ledger CI / build-test (push) Has been cancelled
Findings Ledger CI / migration-validation (push) Has been cancelled
Findings Ledger CI / generate-manifest (push) Has been cancelled
Manifest Integrity / Validate Schema Integrity (push) Has been cancelled
Lighthouse CI / Lighthouse Audit (push) Has been cancelled
Lighthouse CI / Axe Accessibility Audit (push) Has been cancelled
Manifest Integrity / Validate Contract Documents (push) Has been cancelled
Manifest Integrity / Validate Pack Fixtures (push) Has been cancelled
Manifest Integrity / Audit SHA256SUMS Files (push) Has been cancelled
Manifest Integrity / Verify Merkle Roots (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
Policy Simulation / policy-simulate (push) Has been cancelled
- Implemented tests for Cryptographic Failures (A02) to ensure proper handling of sensitive data, secure algorithms, and key management. - Added tests for Security Misconfiguration (A05) to validate production configurations, security headers, CORS settings, and feature management. - Developed tests for Authentication Failures (A07) to enforce strong password policies, rate limiting, session management, and MFA support. - Created tests for Software and Data Integrity Failures (A08) to verify artifact signatures, SBOM integrity, attestation chains, and feed updates.
142 lines
4.5 KiB
C#
142 lines
4.5 KiB
C#
// =============================================================================
|
|
// DsseAttestationParserTests.cs
|
|
// Golden-file tests for DSSE attestation parsing
|
|
// Part of Task T24: Golden-file tests for determinism
|
|
// =============================================================================
|
|
|
|
using FluentAssertions;
|
|
using StellaOps.AirGap.Importer.Reconciliation.Parsers;
|
|
|
|
namespace StellaOps.AirGap.Importer.Tests.Reconciliation;
|
|
|
|
public sealed class DsseAttestationParserTests
|
|
{
|
|
private static readonly string FixturesPath = Path.Combine(
|
|
AppDomain.CurrentDomain.BaseDirectory,
|
|
"Reconciliation", "Fixtures");
|
|
|
|
[Fact]
|
|
public async Task ParseAsync_ValidDsse_ExtractsEnvelope()
|
|
{
|
|
// Arrange
|
|
var parser = new DsseAttestationParser();
|
|
var filePath = Path.Combine(FixturesPath, "sample.intoto.json");
|
|
|
|
if (!File.Exists(filePath))
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Act
|
|
var result = await parser.ParseAsync(filePath);
|
|
|
|
// Assert
|
|
result.IsSuccess.Should().BeTrue();
|
|
result.Envelope.Should().NotBeNull();
|
|
result.Envelope!.PayloadType.Should().Be("application/vnd.in-toto+json");
|
|
result.Envelope.Signatures.Should().HaveCount(1);
|
|
result.Envelope.Signatures[0].KeyId.Should().Be("test-key-id");
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ParseAsync_ValidDsse_ExtractsStatement()
|
|
{
|
|
// Arrange
|
|
var parser = new DsseAttestationParser();
|
|
var filePath = Path.Combine(FixturesPath, "sample.intoto.json");
|
|
|
|
if (!File.Exists(filePath))
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Act
|
|
var result = await parser.ParseAsync(filePath);
|
|
|
|
// Assert
|
|
result.Statement.Should().NotBeNull();
|
|
result.Statement!.Type.Should().Be("https://in-toto.io/Statement/v1");
|
|
result.Statement.PredicateType.Should().Be("https://slsa.dev/provenance/v1");
|
|
result.Statement.Subjects.Should().HaveCount(1);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ParseAsync_ExtractsSubjectDigests()
|
|
{
|
|
// Arrange
|
|
var parser = new DsseAttestationParser();
|
|
var filePath = Path.Combine(FixturesPath, "sample.intoto.json");
|
|
|
|
if (!File.Exists(filePath))
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Act
|
|
var result = await parser.ParseAsync(filePath);
|
|
|
|
// Assert
|
|
var subject = result.Statement!.Subjects[0];
|
|
subject.Name.Should().Be("test-app");
|
|
subject.GetSha256Digest().Should().Be("sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855");
|
|
}
|
|
|
|
[Fact]
|
|
public void IsAttestation_DsseFile_ReturnsTrue()
|
|
{
|
|
var parser = new DsseAttestationParser();
|
|
parser.IsAttestation("test.intoto.json").Should().BeTrue();
|
|
parser.IsAttestation("test.intoto.jsonl").Should().BeTrue();
|
|
parser.IsAttestation("test.dsig").Should().BeTrue();
|
|
parser.IsAttestation("test.dsse").Should().BeTrue();
|
|
}
|
|
|
|
[Fact]
|
|
public void IsAttestation_NonDsseFile_ReturnsFalse()
|
|
{
|
|
var parser = new DsseAttestationParser();
|
|
parser.IsAttestation("test.json").Should().BeFalse();
|
|
parser.IsAttestation("test.cdx.json").Should().BeFalse();
|
|
parser.IsAttestation("test.spdx.json").Should().BeFalse();
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ParseAsync_Deterministic_SameOutputForSameInput()
|
|
{
|
|
// Arrange
|
|
var parser = new DsseAttestationParser();
|
|
var filePath = Path.Combine(FixturesPath, "sample.intoto.json");
|
|
|
|
if (!File.Exists(filePath))
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Act - parse twice
|
|
var result1 = await parser.ParseAsync(filePath);
|
|
var result2 = await parser.ParseAsync(filePath);
|
|
|
|
// Assert - results should be identical
|
|
result1.Statement!.PredicateType.Should().Be(result2.Statement!.PredicateType);
|
|
result1.Statement.Subjects.Count.Should().Be(result2.Statement.Subjects.Count);
|
|
result1.Statement.Subjects[0].GetSha256Digest()
|
|
.Should().Be(result2.Statement.Subjects[0].GetSha256Digest());
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ParseAsync_InvalidJson_ReturnsFailure()
|
|
{
|
|
// Arrange
|
|
var parser = new DsseAttestationParser();
|
|
var json = "not valid json";
|
|
using var stream = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(json));
|
|
|
|
// Act
|
|
var result = await parser.ParseAsync(stream);
|
|
|
|
// Assert
|
|
result.IsSuccess.Should().BeFalse();
|
|
result.ErrorMessage.Should().Contain("parsing error");
|
|
}
|
|
}
|