136 lines
5.5 KiB
C#
136 lines
5.5 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Text.Json;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using StellaOps.Notify.Engine;
|
|
using StellaOps.Notify.Models;
|
|
using Xunit;
|
|
|
|
namespace StellaOps.Notify.Connectors.Teams.Tests;
|
|
|
|
public sealed class TeamsChannelTestProviderTests
|
|
{
|
|
[Fact]
|
|
public async Task BuildPreviewAsync_EmitsFallbackMetadata()
|
|
{
|
|
var provider = new TeamsChannelTestProvider();
|
|
var channel = CreateChannel(
|
|
endpoint: "https://contoso.webhook.office.com/webhookb2/tenant@uuid/IncomingWebhook/abcdef0123456789",
|
|
properties: new Dictionary<string, string>
|
|
{
|
|
["team"] = "secops",
|
|
["webhookKey"] = "s3cr3t-value-with-key-fragment",
|
|
["tenant"] = "contoso.onmicrosoft.com"
|
|
});
|
|
|
|
var request = new ChannelTestPreviewRequest(
|
|
TargetOverride: null,
|
|
TemplateId: null,
|
|
Title: "Notify Critical Finding",
|
|
Summary: "Critical container vulnerability detected.",
|
|
Body: "CVSS 9.8 vulnerability detected in ubuntu:22.04 base layer.",
|
|
TextBody: null,
|
|
Locale: "en-US",
|
|
Metadata: new Dictionary<string, string>(),
|
|
Attachments: new List<string>());
|
|
|
|
var context = new ChannelTestPreviewContext(
|
|
channel.TenantId,
|
|
channel,
|
|
channel.Config.Endpoint!,
|
|
request,
|
|
new DateTimeOffset(2025, 10, 20, 10, 0, 0, TimeSpan.Zero),
|
|
TraceId: "trace-teams-001");
|
|
|
|
var result = await provider.BuildPreviewAsync(context, CancellationToken.None);
|
|
|
|
Assert.Equal(NotifyChannelType.Teams, result.Preview.ChannelType);
|
|
Assert.Equal(channel.Config.Endpoint, result.Preview.Target);
|
|
Assert.Equal("Critical container vulnerability detected.", result.Preview.Summary);
|
|
|
|
Assert.NotNull(result.Metadata);
|
|
Assert.Equal(channel.Config.Endpoint, result.Metadata["teams.webhook"]);
|
|
Assert.Equal("1.5", result.Metadata["teams.card.version"]);
|
|
|
|
var fallback = result.Metadata["teams.fallbackText"];
|
|
Assert.Equal(result.Preview.TextBody, fallback);
|
|
Assert.Equal("Critical container vulnerability detected.", fallback);
|
|
|
|
Assert.Equal(ComputeSecretHash(channel.Config.SecretRef), result.Metadata["teams.secretRef.hash"]);
|
|
Assert.Equal("***", result.Metadata["teams.config.webhookKey"]);
|
|
Assert.Equal("contoso.onmicrosoft.com", result.Metadata["teams.config.tenant"]);
|
|
Assert.Equal(channel.Config.Endpoint, result.Metadata["teams.config.endpoint"]);
|
|
|
|
using var payload = JsonDocument.Parse(result.Preview.Body);
|
|
Assert.Equal("message", payload.RootElement.GetProperty("type").GetString());
|
|
Assert.Equal(result.Preview.TextBody, payload.RootElement.GetProperty("text").GetString());
|
|
Assert.Equal(result.Preview.Summary, payload.RootElement.GetProperty("summary").GetString());
|
|
|
|
var attachments = payload.RootElement.GetProperty("attachments");
|
|
Assert.True(attachments.GetArrayLength() > 0);
|
|
Assert.Equal(
|
|
"AdaptiveCard",
|
|
attachments[0].GetProperty("content").GetProperty("type").GetString());
|
|
}
|
|
|
|
[Fact]
|
|
public async Task BuildPreviewAsync_TruncatesLongFallback()
|
|
{
|
|
var provider = new TeamsChannelTestProvider();
|
|
var channel = CreateChannel(
|
|
endpoint: "https://contoso.webhook.office.com/webhookb2/tenant@uuid/IncomingWebhook/abcdef0123456789",
|
|
properties: new Dictionary<string, string>());
|
|
|
|
var longText = new string('A', 600);
|
|
|
|
var request = new ChannelTestPreviewRequest(
|
|
TargetOverride: null,
|
|
TemplateId: null,
|
|
Title: null,
|
|
Summary: null,
|
|
Body: null,
|
|
TextBody: longText,
|
|
Locale: null,
|
|
Metadata: new Dictionary<string, string>(),
|
|
Attachments: new List<string>());
|
|
|
|
var context = new ChannelTestPreviewContext(
|
|
channel.TenantId,
|
|
channel,
|
|
channel.Config.Endpoint!,
|
|
request,
|
|
DateTimeOffset.UtcNow,
|
|
TraceId: "trace-teams-002");
|
|
|
|
var result = await provider.BuildPreviewAsync(context, CancellationToken.None);
|
|
|
|
var metadata = Assert.IsAssignableFrom<IReadOnlyDictionary<string, string>>(result.Metadata);
|
|
var fallback = Assert.IsType<string>(result.Preview.TextBody);
|
|
Assert.Equal(512, fallback.Length);
|
|
Assert.Equal(fallback, metadata["teams.fallbackText"]);
|
|
Assert.StartsWith(new string('A', 512), fallback);
|
|
}
|
|
|
|
private static NotifyChannel CreateChannel(string endpoint, IDictionary<string, string> properties)
|
|
{
|
|
return NotifyChannel.Create(
|
|
channelId: "channel-teams-sec-ops",
|
|
tenantId: "tenant-sec",
|
|
name: "teams:sec-ops",
|
|
type: NotifyChannelType.Teams,
|
|
config: NotifyChannelConfig.Create(
|
|
secretRef: "ref://notify/channels/teams/sec-ops",
|
|
target: null,
|
|
endpoint: endpoint,
|
|
properties: properties));
|
|
}
|
|
|
|
private static string ComputeSecretHash(string secretRef)
|
|
{
|
|
var bytes = System.Text.Encoding.UTF8.GetBytes(secretRef.Trim());
|
|
var hash = System.Security.Cryptography.SHA256.HashData(bytes);
|
|
return Convert.ToHexString(hash.AsSpan(0, 8)).ToLowerInvariant();
|
|
}
|
|
}
|