old sprints work, new sprints for exposing functionality via cli, improve code_of_conduct and other agents instructions

This commit is contained in:
master
2026-01-15 18:37:59 +02:00
parent c631bacee2
commit 88a85cdd92
208 changed files with 32271 additions and 2287 deletions

View File

@@ -0,0 +1,313 @@
// <copyright file="VexStatementChangeEventTests.cs" company="StellaOps">
// SPDX-License-Identifier: AGPL-3.0-or-later
// Sprint: SPRINT_20260112_006_EXCITITOR_vex_change_events (EXC-VEX-004)
// </copyright>
using System;
using System.Collections.Immutable;
using StellaOps.Excititor.Core.Observations;
using Xunit;
namespace StellaOps.Excititor.Core.Tests.Observations;
[Trait("Category", "Unit")]
public sealed class VexStatementChangeEventTests
{
private static readonly DateTimeOffset FixedTimestamp = new(2026, 1, 15, 10, 30, 0, TimeSpan.Zero);
[Fact]
public void CreateStatementAdded_GeneratesDeterministicEventId()
{
// Arrange & Act
var event1 = VexStatementChangeEventFactory.CreateStatementAdded(
tenant: "default",
vulnerabilityId: "CVE-2026-1234",
productKey: "pkg:npm/lodash@4.17.21",
status: "not_affected",
providerId: "vendor:redhat",
observationId: "default:redhat:VEX-2026-0001:v1",
occurredAtUtc: FixedTimestamp);
var event2 = VexStatementChangeEventFactory.CreateStatementAdded(
tenant: "default",
vulnerabilityId: "CVE-2026-1234",
productKey: "pkg:npm/lodash@4.17.21",
status: "not_affected",
providerId: "vendor:redhat",
observationId: "default:redhat:VEX-2026-0001:v1",
occurredAtUtc: FixedTimestamp);
// Assert - Same inputs should produce same event ID
Assert.Equal(event1.EventId, event2.EventId);
Assert.StartsWith("vex-evt-", event1.EventId);
Assert.Equal(VexTimelineEventTypes.StatementAdded, event1.EventType);
}
[Fact]
public void CreateStatementAdded_DifferentInputsProduceDifferentEventIds()
{
// Arrange & Act
var event1 = VexStatementChangeEventFactory.CreateStatementAdded(
tenant: "default",
vulnerabilityId: "CVE-2026-1234",
productKey: "pkg:npm/lodash@4.17.21",
status: "not_affected",
providerId: "vendor:redhat",
observationId: "default:redhat:VEX-2026-0001:v1",
occurredAtUtc: FixedTimestamp);
var event2 = VexStatementChangeEventFactory.CreateStatementAdded(
tenant: "default",
vulnerabilityId: "CVE-2026-5678", // Different CVE
productKey: "pkg:npm/lodash@4.17.21",
status: "not_affected",
providerId: "vendor:redhat",
observationId: "default:redhat:VEX-2026-0002:v1",
occurredAtUtc: FixedTimestamp);
// Assert - Different inputs should produce different event IDs
Assert.NotEqual(event1.EventId, event2.EventId);
}
[Fact]
public void CreateStatementSuperseded_IncludesSupersedesReference()
{
// Arrange & Act
var evt = VexStatementChangeEventFactory.CreateStatementSuperseded(
tenant: "default",
vulnerabilityId: "CVE-2026-1234",
productKey: "pkg:npm/lodash@4.17.21",
status: "fixed",
previousStatus: "not_affected",
providerId: "vendor:redhat",
observationId: "default:redhat:VEX-2026-0001:v2",
supersedes: ImmutableArray.Create("default:redhat:VEX-2026-0001:v1"),
occurredAtUtc: FixedTimestamp);
// Assert
Assert.Equal(VexTimelineEventTypes.StatementSuperseded, evt.EventType);
Assert.Equal("fixed", evt.NewStatus);
Assert.Equal("not_affected", evt.PreviousStatus);
Assert.Single(evt.Supersedes);
Assert.Equal("default:redhat:VEX-2026-0001:v1", evt.Supersedes[0]);
}
[Fact]
public void CreateConflictDetected_IncludesConflictDetails()
{
// Arrange
var conflictingStatuses = ImmutableArray.Create(
new VexConflictingStatus
{
ProviderId = "vendor:redhat",
Status = "not_affected",
Justification = "CODE_NOT_REACHABLE",
TrustScore = 0.95
},
new VexConflictingStatus
{
ProviderId = "vendor:ubuntu",
Status = "affected",
Justification = null,
TrustScore = 0.85
});
// Act
var evt = VexStatementChangeEventFactory.CreateConflictDetected(
tenant: "default",
vulnerabilityId: "CVE-2026-1234",
productKey: "pkg:npm/lodash@4.17.21",
conflictType: "status_mismatch",
conflictingStatuses: conflictingStatuses,
occurredAtUtc: FixedTimestamp);
// Assert
Assert.Equal(VexTimelineEventTypes.StatementConflict, evt.EventType);
Assert.NotNull(evt.ConflictDetails);
Assert.Equal("status_mismatch", evt.ConflictDetails!.ConflictType);
Assert.Equal(2, evt.ConflictDetails.ConflictingStatuses.Length);
Assert.False(evt.ConflictDetails.AutoResolved);
}
[Fact]
public void ConflictDetails_SortsStatusesByProviderId()
{
// Arrange - Providers in wrong order
var conflictingStatuses = ImmutableArray.Create(
new VexConflictingStatus
{
ProviderId = "vendor:ubuntu",
Status = "affected",
Justification = null,
TrustScore = 0.85
},
new VexConflictingStatus
{
ProviderId = "vendor:redhat",
Status = "not_affected",
Justification = "CODE_NOT_REACHABLE",
TrustScore = 0.95
});
// Act
var evt = VexStatementChangeEventFactory.CreateConflictDetected(
tenant: "default",
vulnerabilityId: "CVE-2026-1234",
productKey: "pkg:npm/lodash@4.17.21",
conflictType: "status_mismatch",
conflictingStatuses: conflictingStatuses,
occurredAtUtc: FixedTimestamp);
// Assert - Should be sorted by provider ID for determinism
Assert.Equal("vendor:redhat", evt.ConflictDetails!.ConflictingStatuses[0].ProviderId);
Assert.Equal("vendor:ubuntu", evt.ConflictDetails.ConflictingStatuses[1].ProviderId);
}
[Fact]
public void EventId_IsIdempotentAcrossMultipleInvocations()
{
// Arrange
var provenance = new VexStatementProvenance
{
DocumentHash = "sha256:abc123",
DocumentUri = "https://vendor.example.com/vex/VEX-2026-0001.json",
SourceTimestamp = FixedTimestamp.AddHours(-1),
Author = "security@vendor.example.com",
TrustScore = 0.95
};
// Act - Create same event multiple times
var events = new VexStatementChangeEvent[5];
for (int i = 0; i < 5; i++)
{
events[i] = VexStatementChangeEventFactory.CreateStatementAdded(
tenant: "default",
vulnerabilityId: "CVE-2026-1234",
productKey: "pkg:npm/lodash@4.17.21",
status: "not_affected",
providerId: "vendor:redhat",
observationId: "default:redhat:VEX-2026-0001:v1",
occurredAtUtc: FixedTimestamp,
provenance: provenance);
}
// 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 CreateStatusChanged_TracksStatusTransition()
{
// Arrange & Act
var evt = VexStatementChangeEventFactory.CreateStatusChanged(
tenant: "default",
vulnerabilityId: "CVE-2026-1234",
productKey: "pkg:npm/lodash@4.17.21",
newStatus: "fixed",
previousStatus: "affected",
providerId: "vendor:redhat",
observationId: "default:redhat:VEX-2026-0001:v3",
occurredAtUtc: FixedTimestamp);
// Assert
Assert.Equal(VexTimelineEventTypes.StatusChanged, evt.EventType);
Assert.Equal("fixed", evt.NewStatus);
Assert.Equal("affected", evt.PreviousStatus);
}
[Fact]
public void EventOrdering_DeterministicByTimestampThenProvider()
{
// Arrange - Create events with same timestamp but different providers
var events = new[]
{
VexStatementChangeEventFactory.CreateStatementAdded(
tenant: "default",
vulnerabilityId: "CVE-2026-1234",
productKey: "pkg:npm/lodash@4.17.21",
status: "not_affected",
providerId: "vendor:ubuntu",
observationId: "default:ubuntu:VEX-2026-0001:v1",
occurredAtUtc: FixedTimestamp),
VexStatementChangeEventFactory.CreateStatementAdded(
tenant: "default",
vulnerabilityId: "CVE-2026-1234",
productKey: "pkg:npm/lodash@4.17.21",
status: "affected",
providerId: "vendor:redhat",
observationId: "default:redhat:VEX-2026-0001:v1",
occurredAtUtc: FixedTimestamp),
VexStatementChangeEventFactory.CreateStatementAdded(
tenant: "default",
vulnerabilityId: "CVE-2026-1234",
productKey: "pkg:npm/lodash@4.17.21",
status: "under_investigation",
providerId: "vendor:debian",
observationId: "default:debian:VEX-2026-0001:v1",
occurredAtUtc: FixedTimestamp),
};
// Act - Sort by (timestamp, providerId) for deterministic ordering
var sorted = events
.OrderBy(e => e.OccurredAtUtc)
.ThenBy(e => e.ProviderId)
.ToArray();
// Assert - Should be sorted by provider ID alphabetically
Assert.Equal("vendor:debian", sorted[0].ProviderId);
Assert.Equal("vendor:redhat", sorted[1].ProviderId);
Assert.Equal("vendor:ubuntu", sorted[2].ProviderId);
}
[Fact]
public void Provenance_PreservedInEvent()
{
// Arrange
var provenance = new VexStatementProvenance
{
DocumentHash = "sha256:abc123def456",
DocumentUri = "https://vendor.example.com/vex/VEX-2026-0001.json",
SourceTimestamp = new DateTimeOffset(2026, 1, 15, 9, 0, 0, TimeSpan.Zero),
Author = "security@vendor.example.com",
TrustScore = 0.95
};
// Act
var evt = VexStatementChangeEventFactory.CreateStatementAdded(
tenant: "default",
vulnerabilityId: "CVE-2026-1234",
productKey: "pkg:npm/lodash@4.17.21",
status: "not_affected",
providerId: "vendor:redhat",
observationId: "default:redhat:VEX-2026-0001:v1",
occurredAtUtc: FixedTimestamp,
provenance: provenance);
// Assert
Assert.NotNull(evt.Provenance);
Assert.Equal("sha256:abc123def456", evt.Provenance!.DocumentHash);
Assert.Equal("https://vendor.example.com/vex/VEX-2026-0001.json", evt.Provenance.DocumentUri);
Assert.Equal(0.95, evt.Provenance.TrustScore);
}
[Fact]
public void TenantNormalization_LowerCasesAndTrims()
{
// Arrange & Act
var evt = VexStatementChangeEventFactory.CreateStatementAdded(
tenant: " DEFAULT ",
vulnerabilityId: "CVE-2026-1234",
productKey: "pkg:npm/lodash@4.17.21",
status: "not_affected",
providerId: "vendor:redhat",
observationId: "default:redhat:VEX-2026-0001:v1",
occurredAtUtc: FixedTimestamp);
// Assert - Tenant should be normalized
Assert.Equal("default", evt.Tenant);
}
}