Add signal contracts for reachability, exploitability, trust, and unknown symbols
- Introduced `ReachabilityState`, `RuntimeHit`, `ExploitabilitySignal`, `ReachabilitySignal`, `SignalEnvelope`, `SignalType`, `TrustSignal`, and `UnknownSymbolSignal` records to define various signal types and their properties. - Implemented JSON serialization attributes for proper data interchange. - Created project files for the new signal contracts library and corresponding test projects. - Added deterministic test fixtures for micro-interaction testing. - Included cryptographic keys for secure operations with cosign.
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using Xunit;
|
||||
|
||||
namespace StellaOps.EvidenceLocker.Tests;
|
||||
|
||||
public sealed class GoldenFixturesTests
|
||||
{
|
||||
private static readonly JsonSerializerOptions JsonOptions = new(JsonSerializerDefaults.Web);
|
||||
|
||||
[Fact]
|
||||
public void SealedBundle_Fixture_HashAndSubjectMatch()
|
||||
{
|
||||
var root = FixturePath("sealed");
|
||||
var manifest = ReadJson(Path.Combine(root, "manifest.json"));
|
||||
var checksums = ReadJson(Path.Combine(root, "checksums.txt"));
|
||||
var signature = ReadJson(Path.Combine(root, "signature.json"));
|
||||
var expected = ReadJson(Path.Combine(root, "expected.json"));
|
||||
|
||||
var rootFromChecksums = checksums.GetProperty("root").GetString();
|
||||
Assert.Equal(expected.GetProperty("merkleRoot").GetString(), rootFromChecksums);
|
||||
|
||||
var subject = signature.GetProperty("signatures")[0].GetProperty("subjectMerkleRoot").GetString();
|
||||
Assert.Equal(rootFromChecksums, subject);
|
||||
|
||||
var entries = manifest.GetProperty("entries").EnumerateArray().Select(e => e.GetProperty("canonicalPath").GetString()).ToArray();
|
||||
var checksumEntries = checksums.GetProperty("entries").EnumerateArray().Select(e => e.GetProperty("canonicalPath").GetString()).ToArray();
|
||||
Assert.Equal(entries.OrderBy(x => x), checksumEntries.OrderBy(x => x));
|
||||
|
||||
// Recompute sha256(checksums.txt) to match DSSE subject binding rule
|
||||
var checksumJson = File.ReadAllText(Path.Combine(root, "checksums.txt"));
|
||||
var recomputedSubject = Convert.ToHexString(SHA256.HashData(Encoding.UTF8.GetBytes(checksumJson))).ToLowerInvariant();
|
||||
Assert.Equal(rootFromChecksums, recomputedSubject);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PortableBundle_Fixture_RedactionAndSubjectMatch()
|
||||
{
|
||||
var root = FixturePath("portable");
|
||||
var manifest = ReadJson(Path.Combine(root, "manifest.json"));
|
||||
var checksums = ReadJson(Path.Combine(root, "checksums.txt"));
|
||||
var expected = ReadJson(Path.Combine(root, "expected.json"));
|
||||
|
||||
Assert.True(manifest.GetProperty("redaction").GetProperty("portable").GetBoolean());
|
||||
Assert.DoesNotContain("tenant", File.ReadAllText(Path.Combine(root, "bundle.json")), StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
var rootFromChecksums = checksums.GetProperty("root").GetString();
|
||||
Assert.Equal(expected.GetProperty("merkleRoot").GetString(), rootFromChecksums);
|
||||
|
||||
var checksumJson = File.ReadAllText(Path.Combine(root, "checksums.txt"));
|
||||
var recomputedSubject = Convert.ToHexString(SHA256.HashData(Encoding.UTF8.GetBytes(checksumJson))).ToLowerInvariant();
|
||||
Assert.Equal(rootFromChecksums, recomputedSubject);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReplayFixture_RecordDigestMatches()
|
||||
{
|
||||
var root = FixturePath("replay");
|
||||
var replayPath = Path.Combine(root, "replay.ndjson");
|
||||
var replayContent = File.ReadAllBytes(replayPath);
|
||||
var expected = ReadJson(Path.Combine(root, "expected.json"));
|
||||
|
||||
var hash = "sha256:" + Convert.ToHexString(SHA256.HashData(replayContent)).ToLowerInvariant();
|
||||
Assert.Equal(expected.GetProperty("recordDigest").GetString(), hash);
|
||||
}
|
||||
|
||||
private static string FixturePath(string relative) =>
|
||||
Path.Combine(AppContext.BaseDirectory, "Fixtures", relative);
|
||||
|
||||
private static JsonElement ReadJson(string path)
|
||||
{
|
||||
using var doc = JsonDocument.Parse(File.ReadAllText(path), new JsonDocumentOptions { AllowTrailingCommas = true });
|
||||
return doc.RootElement.Clone();
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,9 @@
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="xunit.runner.json" CopyToOutputDirectory="PreserveNewest" />
|
||||
<Content Include="../../../tests/EvidenceLocker/Bundles/Golden/**/*.*"
|
||||
CopyToOutputDirectory="PreserveNewest"
|
||||
Link="Fixtures/%(RecursiveDir)%(Filename)%(Extension)" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
Reference in New Issue
Block a user