old sprints work, new sprints for exposing functionality via cli, improve code_of_conduct and other agents instructions
This commit is contained in:
@@ -0,0 +1,276 @@
|
||||
// <copyright file="RekorEntryEventTests.cs" company="StellaOps">
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
// Sprint: SPRINT_20260112_007_ATTESTOR_rekor_entry_events (ATT-REKOR-004)
|
||||
// </copyright>
|
||||
|
||||
using System;
|
||||
using System.Collections.Immutable;
|
||||
using StellaOps.Attestor.Core.Rekor;
|
||||
using Xunit;
|
||||
|
||||
namespace StellaOps.Attestor.Core.Tests.Rekor;
|
||||
|
||||
[Trait("Category", "Unit")]
|
||||
public sealed class RekorEntryEventTests
|
||||
{
|
||||
private static readonly DateTimeOffset FixedTimestamp = new(2026, 1, 15, 10, 30, 0, TimeSpan.Zero);
|
||||
|
||||
[Fact]
|
||||
public void CreateEntryLogged_GeneratesDeterministicEventId()
|
||||
{
|
||||
// Arrange & Act
|
||||
var event1 = RekorEntryEventFactory.CreateEntryLogged(
|
||||
tenant: "default",
|
||||
bundleDigest: "sha256:abc123def456",
|
||||
predicateType: "StellaOps.ScanResults@1",
|
||||
logIndex: 123456789,
|
||||
logId: "c0d23d6ad406973f",
|
||||
entryUuid: "24296fb24b8ad77a",
|
||||
integratedTime: 1736937002,
|
||||
createdAtUtc: FixedTimestamp);
|
||||
|
||||
var event2 = RekorEntryEventFactory.CreateEntryLogged(
|
||||
tenant: "default",
|
||||
bundleDigest: "sha256:abc123def456",
|
||||
predicateType: "StellaOps.ScanResults@1",
|
||||
logIndex: 123456789,
|
||||
logId: "c0d23d6ad406973f",
|
||||
entryUuid: "24296fb24b8ad77a",
|
||||
integratedTime: 1736937002,
|
||||
createdAtUtc: FixedTimestamp);
|
||||
|
||||
// Assert - Same inputs should produce same event ID
|
||||
Assert.Equal(event1.EventId, event2.EventId);
|
||||
Assert.StartsWith("rekor-evt-", event1.EventId);
|
||||
Assert.Equal(RekorEventTypes.EntryLogged, event1.EventType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateEntryLogged_DifferentLogIndexProducesDifferentEventId()
|
||||
{
|
||||
// Arrange & Act
|
||||
var event1 = RekorEntryEventFactory.CreateEntryLogged(
|
||||
tenant: "default",
|
||||
bundleDigest: "sha256:abc123def456",
|
||||
predicateType: "StellaOps.ScanResults@1",
|
||||
logIndex: 123456789,
|
||||
logId: "c0d23d6ad406973f",
|
||||
entryUuid: "24296fb24b8ad77a",
|
||||
integratedTime: 1736937002,
|
||||
createdAtUtc: FixedTimestamp);
|
||||
|
||||
var event2 = RekorEntryEventFactory.CreateEntryLogged(
|
||||
tenant: "default",
|
||||
bundleDigest: "sha256:abc123def456",
|
||||
predicateType: "StellaOps.ScanResults@1",
|
||||
logIndex: 987654321, // Different log index
|
||||
logId: "c0d23d6ad406973f",
|
||||
entryUuid: "different-uuid",
|
||||
integratedTime: 1736937002,
|
||||
createdAtUtc: FixedTimestamp);
|
||||
|
||||
// Assert
|
||||
Assert.NotEqual(event1.EventId, event2.EventId);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateEntryQueued_HasCorrectEventType()
|
||||
{
|
||||
// Arrange & Act
|
||||
var evt = RekorEntryEventFactory.CreateEntryQueued(
|
||||
tenant: "default",
|
||||
bundleDigest: "sha256:abc123def456",
|
||||
predicateType: "StellaOps.VEXAttestation@1",
|
||||
queuedAtUtc: FixedTimestamp);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(RekorEventTypes.EntryQueued, evt.EventType);
|
||||
Assert.Equal(0, evt.LogIndex);
|
||||
Assert.False(evt.InclusionVerified);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateInclusionVerified_HasCorrectEventType()
|
||||
{
|
||||
// Arrange & Act
|
||||
var evt = RekorEntryEventFactory.CreateInclusionVerified(
|
||||
tenant: "default",
|
||||
bundleDigest: "sha256:abc123def456",
|
||||
predicateType: "StellaOps.ScanResults@1",
|
||||
logIndex: 123456789,
|
||||
logId: "c0d23d6ad406973f",
|
||||
entryUuid: "24296fb24b8ad77a",
|
||||
integratedTime: 1736937002,
|
||||
verifiedAtUtc: FixedTimestamp);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(RekorEventTypes.InclusionVerified, evt.EventType);
|
||||
Assert.True(evt.InclusionVerified);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateEntryFailed_HasCorrectEventType()
|
||||
{
|
||||
// Arrange & Act
|
||||
var evt = RekorEntryEventFactory.CreateEntryFailed(
|
||||
tenant: "default",
|
||||
bundleDigest: "sha256:abc123def456",
|
||||
predicateType: "StellaOps.ScanResults@1",
|
||||
reason: "rekor_unavailable",
|
||||
failedAtUtc: FixedTimestamp);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(RekorEventTypes.EntryFailed, evt.EventType);
|
||||
Assert.False(evt.InclusionVerified);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EventIdIsIdempotentAcrossMultipleInvocations()
|
||||
{
|
||||
// Arrange & Act - Create same event multiple times
|
||||
var events = new RekorEntryEvent[5];
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
events[i] = RekorEntryEventFactory.CreateEntryLogged(
|
||||
tenant: "default",
|
||||
bundleDigest: "sha256:abc123def456",
|
||||
predicateType: "StellaOps.ScanResults@1",
|
||||
logIndex: 123456789,
|
||||
logId: "c0d23d6ad406973f",
|
||||
entryUuid: "24296fb24b8ad77a",
|
||||
integratedTime: 1736937002,
|
||||
createdAtUtc: FixedTimestamp);
|
||||
}
|
||||
|
||||
// Assert - All event IDs should be identical
|
||||
var firstEventId = events[0].EventId;
|
||||
foreach (var evt in events)
|
||||
{
|
||||
Assert.Equal(firstEventId, evt.EventId);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ExtractReanalysisHints_ScanResults_ReturnsImmediateScope()
|
||||
{
|
||||
// Arrange
|
||||
var cveIds = ImmutableArray.Create("CVE-2026-1234", "CVE-2026-5678");
|
||||
var productKeys = ImmutableArray.Create("pkg:npm/lodash@4.17.21");
|
||||
|
||||
// Act
|
||||
var hints = RekorReanalysisHintsFactory.Create(
|
||||
predicateType: "StellaOps.ScanResults@1",
|
||||
cveIds: cveIds,
|
||||
productKeys: productKeys,
|
||||
artifactDigests: ImmutableArray<string>.Empty);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(ReanalysisScope.Immediate, hints.ReanalysisScope);
|
||||
Assert.True(hints.MayAffectDecision);
|
||||
Assert.Equal(2, hints.CveIds.Length);
|
||||
Assert.Single(hints.ProductKeys);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ExtractReanalysisHints_VEXAttestation_ReturnsImmediateScope()
|
||||
{
|
||||
// Arrange & Act
|
||||
var hints = RekorReanalysisHintsFactory.Create(
|
||||
predicateType: "StellaOps.VEXAttestation@1",
|
||||
cveIds: ImmutableArray.Create("CVE-2026-1234"),
|
||||
productKeys: ImmutableArray.Create("pkg:npm/express@4.18.0"),
|
||||
artifactDigests: ImmutableArray<string>.Empty);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(ReanalysisScope.Immediate, hints.ReanalysisScope);
|
||||
Assert.True(hints.MayAffectDecision);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ExtractReanalysisHints_SBOMAttestation_ReturnsScheduledScope()
|
||||
{
|
||||
// Arrange & Act
|
||||
var hints = RekorReanalysisHintsFactory.Create(
|
||||
predicateType: "StellaOps.SBOMAttestation@1",
|
||||
cveIds: ImmutableArray<string>.Empty,
|
||||
productKeys: ImmutableArray.Create("pkg:npm/myapp@1.0.0"),
|
||||
artifactDigests: ImmutableArray<string>.Empty);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(ReanalysisScope.Scheduled, hints.ReanalysisScope);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ExtractReanalysisHints_BuildProvenance_ReturnsNoneScope()
|
||||
{
|
||||
// Arrange & Act
|
||||
var hints = RekorReanalysisHintsFactory.Create(
|
||||
predicateType: "StellaOps.BuildProvenance@1",
|
||||
cveIds: ImmutableArray<string>.Empty,
|
||||
productKeys: ImmutableArray<string>.Empty,
|
||||
artifactDigests: ImmutableArray<string>.Empty);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(ReanalysisScope.None, hints.ReanalysisScope);
|
||||
Assert.False(hints.MayAffectDecision);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TenantNormalization_LowerCasesAndTrims()
|
||||
{
|
||||
// Arrange & Act
|
||||
var evt = RekorEntryEventFactory.CreateEntryLogged(
|
||||
tenant: " DEFAULT ",
|
||||
bundleDigest: "sha256:abc123def456",
|
||||
predicateType: "StellaOps.ScanResults@1",
|
||||
logIndex: 123456789,
|
||||
logId: "c0d23d6ad406973f",
|
||||
entryUuid: "24296fb24b8ad77a",
|
||||
integratedTime: 1736937002,
|
||||
createdAtUtc: FixedTimestamp);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("default", evt.Tenant);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IntegratedTimeRfc3339_FormattedCorrectly()
|
||||
{
|
||||
// Arrange & Act
|
||||
var evt = RekorEntryEventFactory.CreateEntryLogged(
|
||||
tenant: "default",
|
||||
bundleDigest: "sha256:abc123def456",
|
||||
predicateType: "StellaOps.ScanResults@1",
|
||||
logIndex: 123456789,
|
||||
logId: "c0d23d6ad406973f",
|
||||
entryUuid: "24296fb24b8ad77a",
|
||||
integratedTime: 1736937002, // 2025-01-15T10:30:02Z
|
||||
createdAtUtc: FixedTimestamp);
|
||||
|
||||
// Assert - Should be RFC3339 formatted
|
||||
Assert.Contains("2025-01-15", evt.IntegratedTimeRfc3339);
|
||||
Assert.EndsWith("Z", evt.IntegratedTimeRfc3339);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReanalysisHints_SortsCveIdsAndProductKeys()
|
||||
{
|
||||
// Arrange - CVEs and products in unsorted order
|
||||
var cveIds = ImmutableArray.Create("CVE-2026-9999", "CVE-2026-0001", "CVE-2026-5000");
|
||||
var productKeys = ImmutableArray.Create("pkg:npm/zod@3.0.0", "pkg:npm/axios@1.0.0");
|
||||
|
||||
// Act
|
||||
var hints = RekorReanalysisHintsFactory.Create(
|
||||
predicateType: "StellaOps.ScanResults@1",
|
||||
cveIds: cveIds,
|
||||
productKeys: productKeys,
|
||||
artifactDigests: ImmutableArray<string>.Empty);
|
||||
|
||||
// Assert - Should be sorted for determinism
|
||||
Assert.Equal("CVE-2026-0001", hints.CveIds[0]);
|
||||
Assert.Equal("CVE-2026-5000", hints.CveIds[1]);
|
||||
Assert.Equal("CVE-2026-9999", hints.CveIds[2]);
|
||||
Assert.Equal("pkg:npm/axios@1.0.0", hints.ProductKeys[0]);
|
||||
Assert.Equal("pkg:npm/zod@3.0.0", hints.ProductKeys[1]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user