Add channel test providers for Email, Slack, Teams, and Webhook
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled

- Implemented EmailChannelTestProvider to generate email preview payloads.
- Implemented SlackChannelTestProvider to create Slack message previews.
- Implemented TeamsChannelTestProvider for generating Teams Adaptive Card previews.
- Implemented WebhookChannelTestProvider to create webhook payloads.
- Added INotifyChannelTestProvider interface for channel-specific preview generation.
- Created ChannelTestPreviewContracts for request and response models.
- Developed NotifyChannelTestService to handle test send requests and generate previews.
- Added rate limit policies for test sends and delivery history.
- Implemented unit tests for service registration and binding.
- Updated project files to include necessary dependencies and configurations.
This commit is contained in:
2025-10-19 23:29:34 +03:00
parent 8e7ce55542
commit 5fd4032c7c
239 changed files with 17245 additions and 3155 deletions

View File

@@ -1,37 +1,12 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
namespace StellaOps.Excititor.Core;
public sealed record VexScoreEnvelope(
DateTimeOffset GeneratedAt,
string PolicyRevisionId,
string? PolicyDigest,
double Alpha,
double Beta,
double WeightCeiling,
ImmutableArray<VexScoreEntry> Entries)
public sealed record VexScoreEnvelope
{
public VexScoreEnvelope(
DateTimeOffset GeneratedAt,
string PolicyRevisionId,
string? PolicyDigest,
double Alpha,
double Beta,
double WeightCeiling,
IEnumerable<VexScoreEntry> Entries)
: this(
GeneratedAt,
PolicyRevisionId,
PolicyDigest,
Alpha,
Beta,
WeightCeiling,
NormalizeEntries(Entries))
{
}
private VexScoreEnvelope(
DateTimeOffset generatedAt,
string policyRevisionId,
string? policyDigest,
@@ -60,13 +35,32 @@ public sealed record VexScoreEnvelope(
throw new ArgumentOutOfRangeException(nameof(weightCeiling), "Weight ceiling must be a finite number greater than zero.");
}
this.GeneratedAt = generatedAt;
this.PolicyRevisionId = policyRevisionId.Trim();
this.PolicyDigest = string.IsNullOrWhiteSpace(policyDigest) ? null : policyDigest.Trim();
this.Alpha = alpha;
this.Beta = beta;
this.WeightCeiling = weightCeiling;
this.Entries = entries;
GeneratedAt = generatedAt;
PolicyRevisionId = policyRevisionId.Trim();
PolicyDigest = string.IsNullOrWhiteSpace(policyDigest) ? null : policyDigest.Trim();
Alpha = alpha;
Beta = beta;
WeightCeiling = weightCeiling;
Entries = entries;
}
public VexScoreEnvelope(
DateTimeOffset generatedAt,
string policyRevisionId,
string? policyDigest,
double alpha,
double beta,
double weightCeiling,
IEnumerable<VexScoreEntry> entries)
: this(
generatedAt,
policyRevisionId,
policyDigest,
alpha,
beta,
weightCeiling,
NormalizeEntries(entries))
{
}
public DateTimeOffset GeneratedAt { get; }
@@ -97,32 +91,9 @@ public sealed record VexScoreEnvelope(
}
}
public sealed record VexScoreEntry(
string VulnerabilityId,
string ProductKey,
VexConsensusStatus Status,
DateTimeOffset CalculatedAt,
VexSignalSnapshot? Signals,
double? Score)
public sealed record VexScoreEntry
{
public VexScoreEntry(
string VulnerabilityId,
string ProductKey,
VexConsensusStatus Status,
DateTimeOffset CalculatedAt,
VexSignalSnapshot? Signals,
double? Score)
: this(
ValidateVulnerability(VulnerabilityId),
ValidateProduct(ProductKey),
Status,
CalculatedAt,
Signals,
ValidateScore(Score))
{
}
private VexScoreEntry(
string vulnerabilityId,
string productKey,
VexConsensusStatus status,
@@ -130,12 +101,12 @@ public sealed record VexScoreEntry(
VexSignalSnapshot? signals,
double? score)
{
VulnerabilityId = vulnerabilityId;
ProductKey = productKey;
VulnerabilityId = ValidateVulnerability(vulnerabilityId);
ProductKey = ValidateProduct(productKey);
Status = status;
CalculatedAt = calculatedAt;
Signals = signals;
Score = score;
Score = ValidateScore(score);
}
public string VulnerabilityId { get; }