up
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
oas-ci / oas-validate (push) Has been cancelled
Signals CI & Image / signals-ci (push) Has been cancelled
sm-remote-ci / build-and-test (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Signals Reachability Scoring & Events / sign-and-upload (push) Has been cancelled
api-governance / spectral-lint (push) Has been cancelled
Signals Reachability Scoring & Events / reachability-smoke (push) Has been cancelled
AOC Guard CI / aoc-guard (push) Has been cancelled
devportal-offline / build-offline (push) Has been cancelled
Mirror Thin Bundle Sign & Verify / mirror-sign (push) Has been cancelled
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
oas-ci / oas-validate (push) Has been cancelled
Signals CI & Image / signals-ci (push) Has been cancelled
sm-remote-ci / build-and-test (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Signals Reachability Scoring & Events / sign-and-upload (push) Has been cancelled
api-governance / spectral-lint (push) Has been cancelled
Signals Reachability Scoring & Events / reachability-smoke (push) Has been cancelled
AOC Guard CI / aoc-guard (push) Has been cancelled
devportal-offline / build-offline (push) Has been cancelled
Mirror Thin Bundle Sign & Verify / mirror-sign (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,118 @@
|
||||
using StellaOps.Cryptography;
|
||||
|
||||
namespace StellaOps.Audit.ReplayToken.Tests;
|
||||
|
||||
public sealed class ReplayTokenGeneratorTests
|
||||
{
|
||||
[Fact]
|
||||
public void Generate_SameInputs_ReturnsSameValue()
|
||||
{
|
||||
var cryptoHash = DefaultCryptoHash.CreateForTests();
|
||||
var fixedNow = new DateTimeOffset(2025, 1, 1, 0, 0, 0, TimeSpan.Zero);
|
||||
var timeProvider = new FixedTimeProvider(fixedNow);
|
||||
|
||||
var generator = new Sha256ReplayTokenGenerator(cryptoHash, timeProvider);
|
||||
|
||||
var request = new ReplayTokenRequest
|
||||
{
|
||||
FeedManifests = new[] { "sha256:bbb", "sha256:aaa" },
|
||||
RulesVersion = "rules-v1",
|
||||
RulesHash = "sha256:rules",
|
||||
LatticePolicyVersion = "lattice-v1",
|
||||
LatticePolicyHash = "sha256:lattice",
|
||||
InputHashes = new[] { "sha256:input2", "sha256:input1" },
|
||||
ScoringConfigVersion = "score-v1",
|
||||
EvidenceHashes = new[] { "sha256:e2", "sha256:e1" },
|
||||
AdditionalContext = new Dictionary<string, string>
|
||||
{
|
||||
["b"] = "2",
|
||||
["a"] = "1"
|
||||
}
|
||||
};
|
||||
|
||||
var token1 = generator.Generate(request);
|
||||
var token2 = generator.Generate(request);
|
||||
|
||||
Assert.Equal(token1.Value, token2.Value);
|
||||
Assert.Equal(token1.Canonical, token2.Canonical);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Generate_IgnoresArrayOrdering()
|
||||
{
|
||||
var cryptoHash = DefaultCryptoHash.CreateForTests();
|
||||
var timeProvider = new FixedTimeProvider(new DateTimeOffset(2025, 1, 1, 0, 0, 0, TimeSpan.Zero));
|
||||
|
||||
var generator = new Sha256ReplayTokenGenerator(cryptoHash, timeProvider);
|
||||
|
||||
var requestA = new ReplayTokenRequest
|
||||
{
|
||||
FeedManifests = new[] { "sha256:aaa", "sha256:bbb" },
|
||||
InputHashes = new[] { "sha256:input1", "sha256:input2" }
|
||||
};
|
||||
|
||||
var requestB = new ReplayTokenRequest
|
||||
{
|
||||
FeedManifests = new[] { "sha256:bbb", "sha256:aaa" },
|
||||
InputHashes = new[] { "sha256:input2", "sha256:input1" }
|
||||
};
|
||||
|
||||
var tokenA = generator.Generate(requestA);
|
||||
var tokenB = generator.Generate(requestB);
|
||||
|
||||
Assert.Equal(tokenA.Value, tokenB.Value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Verify_MatchingInputs_ReturnsTrue()
|
||||
{
|
||||
var cryptoHash = DefaultCryptoHash.CreateForTests();
|
||||
var timeProvider = new FixedTimeProvider(new DateTimeOffset(2025, 1, 1, 0, 0, 0, TimeSpan.Zero));
|
||||
|
||||
var generator = new Sha256ReplayTokenGenerator(cryptoHash, timeProvider);
|
||||
var request = new ReplayTokenRequest { InputHashes = new[] { "sha256:input" } };
|
||||
|
||||
var token = generator.Generate(request);
|
||||
Assert.True(generator.Verify(token, request));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Verify_DifferentInputs_ReturnsFalse()
|
||||
{
|
||||
var cryptoHash = DefaultCryptoHash.CreateForTests();
|
||||
var timeProvider = new FixedTimeProvider(new DateTimeOffset(2025, 1, 1, 0, 0, 0, TimeSpan.Zero));
|
||||
|
||||
var generator = new Sha256ReplayTokenGenerator(cryptoHash, timeProvider);
|
||||
var request = new ReplayTokenRequest { InputHashes = new[] { "sha256:input" } };
|
||||
var different = new ReplayTokenRequest { InputHashes = new[] { "sha256:other" } };
|
||||
|
||||
var token = generator.Generate(request);
|
||||
Assert.False(generator.Verify(token, different));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReplayToken_Parse_RoundTripsCanonical()
|
||||
{
|
||||
var token = new ReplayToken("0123456789abcdef", DateTimeOffset.UnixEpoch);
|
||||
var parsed = ReplayToken.Parse(token.Canonical);
|
||||
|
||||
Assert.Equal(token.Value, parsed.Value);
|
||||
Assert.Equal(token.Algorithm, parsed.Algorithm);
|
||||
Assert.Equal(token.Version, parsed.Version);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("")]
|
||||
[InlineData("replay")]
|
||||
[InlineData("replay:v1.0:SHA-256")]
|
||||
[InlineData("other:v1.0:SHA-256:abc")]
|
||||
public void ReplayToken_Parse_Invalid_Throws(string canonical)
|
||||
{
|
||||
Assert.ThrowsAny<Exception>(() => ReplayToken.Parse(canonical));
|
||||
}
|
||||
|
||||
private sealed class FixedTimeProvider(DateTimeOffset now) : TimeProvider
|
||||
{
|
||||
public override DateTimeOffset GetUtcNow() => now;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" ?>
|
||||
<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>
|
||||
<ProjectReference Include="..\\..\\__Libraries\\StellaOps.Audit.ReplayToken\\StellaOps.Audit.ReplayToken.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
Reference in New Issue
Block a user