feat: Add MongoIdempotencyStoreOptions for MongoDB configuration
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled

feat: Implement BsonJsonConverter for converting BsonDocument and BsonArray to JSON

fix: Update project file to include MongoDB.Bson package

test: Add GraphOverlayExporterTests to validate NDJSON export functionality

refactor: Refactor Program.cs in Attestation Tool for improved argument parsing and error handling

docs: Update README for stella-forensic-verify with usage instructions and exit codes

feat: Enhance HmacVerifier with clock skew and not-after checks

feat: Add MerkleRootVerifier and ChainOfCustodyVerifier for additional verification methods

fix: Update DenoRuntimeShim to correctly handle file paths

feat: Introduce ComposerAutoloadData and related parsing in ComposerLockReader

test: Add tests for Deno runtime execution and verification

test: Enhance PHP package tests to include autoload data verification

test: Add unit tests for HmacVerifier and verification logic
This commit is contained in:
StellaOps Bot
2025-11-22 16:42:56 +02:00
parent 967ae0ab16
commit dc7c75b496
85 changed files with 2272 additions and 917 deletions

View File

@@ -149,16 +149,3 @@ public sealed class SignersTests
}
}
}
internal sealed class TestTimeProvider : TimeProvider
{
private DateTimeOffset _now;
public TestTimeProvider(DateTimeOffset now) => _now = now;
public override DateTimeOffset GetUtcNow() => _now;
public override TimeZoneInfo LocalTimeZone => TimeZoneInfo.Utc;
public override long GetTimestamp() => 0L;
public void Advance(TimeSpan delta) => _now = _now.Add(delta);
}

View File

@@ -0,0 +1,16 @@
using System;
namespace StellaOps.Provenance.Attestation.Tests;
internal sealed class TestTimeProvider : TimeProvider
{
private DateTimeOffset _now;
public TestTimeProvider(DateTimeOffset now) => _now = now;
public override DateTimeOffset GetUtcNow() => _now;
public override TimeZoneInfo LocalTimeZone => TimeZoneInfo.Utc;
public override long GetTimestamp() => 0L;
public void Advance(TimeSpan delta) => _now = _now.Add(delta);
}

View File

@@ -0,0 +1,39 @@
using System.Text;
using StellaOps.Provenance.Attestation;
using Xunit;
namespace StellaOps.Provenance.Attestation.Tests;
public sealed class ToolEntrypointTests
{
[Fact]
public async Task RunAsync_ReturnsInvalidOnMissingArgs()
{
var code = await ToolEntrypoint.RunAsync(Array.Empty<string>(), TextWriter.Null, new StringWriter(), new TestTimeProvider(DateTimeOffset.UtcNow));
Assert.Equal(1, code);
}
[Fact]
public async Task RunAsync_VerifiesValidSignature()
{
var payload = Encoding.UTF8.GetBytes("payload");
var key = Convert.ToHexString(Encoding.UTF8.GetBytes("secret"));
using var hmac = new System.Security.Cryptography.HMACSHA256(Encoding.UTF8.GetBytes("secret"));
var sig = Convert.ToHexString(hmac.ComputeHash(payload));
var tmp = Path.GetTempFileName();
await File.WriteAllBytesAsync(tmp, payload);
var stdout = new StringWriter();
var code = await ToolEntrypoint.RunAsync(new[]
{
"--payload", tmp,
"--signature-hex", sig,
"--key-hex", key,
"--signed-at", "2025-11-22T00:00:00Z"
}, stdout, new StringWriter(), new TestTimeProvider(new DateTimeOffset(2025,11,22,0,0,0,TimeSpan.Zero)));
Assert.Equal(0, code);
Assert.Contains("\"valid\":true", stdout.ToString());
}
}

View File

@@ -0,0 +1,73 @@
using System.Text;
using StellaOps.Provenance.Attestation;
using Xunit;
namespace StellaOps.Provenance.Attestation.Tests;
public sealed class VerificationLibraryTests
{
[Fact]
public async Task HmacVerifier_FailsWhenKeyExpired()
{
var key = new InMemoryKeyProvider("k1", Encoding.UTF8.GetBytes("secret"), DateTimeOffset.UtcNow.AddMinutes(-1));
var verifier = new HmacVerifier(key, new TestTimeProvider(DateTimeOffset.UtcNow));
var request = new SignRequest(Encoding.UTF8.GetBytes("payload"), "ct");
var signer = new HmacSigner(key, timeProvider: new TestTimeProvider(DateTimeOffset.UtcNow.AddMinutes(-2)));
var signature = await signer.SignAsync(request);
var result = await verifier.VerifyAsync(request, signature);
Assert.False(result.IsValid);
Assert.Contains("time", result.Reason);
}
[Fact]
public async Task HmacVerifier_FailsWhenClockSkewTooLarge()
{
var now = new DateTimeOffset(2025, 11, 22, 12, 0, 0, TimeSpan.Zero);
var key = new InMemoryKeyProvider("k", Encoding.UTF8.GetBytes("secret"));
var signer = new HmacSigner(key, timeProvider: new TestTimeProvider(now.AddMinutes(10)));
var request = new SignRequest(Encoding.UTF8.GetBytes("payload"), "ct");
var sig = await signer.SignAsync(request);
var verifier = new HmacVerifier(key, new TestTimeProvider(now), TimeSpan.FromMinutes(5));
var result = await verifier.VerifyAsync(request, sig);
Assert.False(result.IsValid);
}
[Fact]
public void MerkleRootVerifier_DetectsMismatch()
{
var leaves = new[]
{
Encoding.UTF8.GetBytes("a"),
Encoding.UTF8.GetBytes("b"),
Encoding.UTF8.GetBytes("c")
};
var expected = Convert.FromHexString("00");
var result = MerkleRootVerifier.VerifyRoot(leaves, expected, new TestTimeProvider(DateTimeOffset.UtcNow));
Assert.False(result.IsValid);
Assert.Equal("merkle root mismatch", result.Reason);
}
[Fact]
public void ChainOfCustodyVerifier_ComputesAggregate()
{
var hops = new[]
{
Encoding.UTF8.GetBytes("hop1"),
Encoding.UTF8.GetBytes("hop2")
};
using var sha = System.Security.Cryptography.SHA256.Create();
var aggregate = sha.ComputeHash(Array.Empty<byte>().Concat(hops[0]).ToArray());
aggregate = sha.ComputeHash(aggregate.Concat(hops[1]).ToArray());
var result = ChainOfCustodyVerifier.Verify(hops, aggregate, new TestTimeProvider(DateTimeOffset.UtcNow));
Assert.True(result.IsValid);
}
}