up
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
AOC Guard CI / aoc-guard (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
SDK Publish & Sign / sdk-publish (push) Has been cancelled
sdk-generator-smoke / sdk-smoke (push) Has been cancelled

This commit is contained in:
StellaOps Bot
2025-11-27 08:51:10 +02:00
parent ea970ead2a
commit c34fb7256d
126 changed files with 18553 additions and 693 deletions

View File

@@ -1,22 +1,32 @@
using System.Net.Http.Json;
using System.Text;
using System.Text.Json;
using Microsoft.Extensions.Logging;
using StellaOps.Notify.Models;
using StellaOps.Notifier.Worker.Security;
namespace StellaOps.Notifier.Worker.Channels;
/// <summary>
/// Channel adapter for webhook (HTTP POST) delivery with retry support.
/// Channel adapter for webhook (HTTP POST) delivery with retry support and HMAC signing.
/// </summary>
public sealed class WebhookChannelAdapter : INotifyChannelAdapter
{
private readonly HttpClient _httpClient;
private readonly IWebhookSecurityService? _securityService;
private readonly TimeProvider _timeProvider;
private readonly ILogger<WebhookChannelAdapter> _logger;
public WebhookChannelAdapter(HttpClient httpClient, ILogger<WebhookChannelAdapter> logger)
public WebhookChannelAdapter(
HttpClient httpClient,
ILogger<WebhookChannelAdapter> logger,
IWebhookSecurityService? securityService = null,
TimeProvider? timeProvider = null)
{
_httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_securityService = securityService;
_timeProvider = timeProvider ?? TimeProvider.System;
}
public NotifyChannelType ChannelType => NotifyChannelType.Webhook;
@@ -52,17 +62,30 @@ public sealed class WebhookChannelAdapter : INotifyChannelAdapter
timestamp = DateTimeOffset.UtcNow
};
var jsonOptions = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase };
var payloadJson = JsonSerializer.Serialize(payload, jsonOptions);
var payloadBytes = Encoding.UTF8.GetBytes(payloadJson);
try
{
using var request = new HttpRequestMessage(HttpMethod.Post, uri);
request.Content = JsonContent.Create(payload, options: new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
});
request.Content = new StringContent(payloadJson, Encoding.UTF8, "application/json");
// Add HMAC signature header if secret is available (placeholder for KMS integration)
// Add version header
request.Headers.Add("X-StellaOps-Notifier", "1.0");
// Add HMAC signature if security service is available
if (_securityService is not null)
{
var timestamp = _timeProvider.GetUtcNow();
var signature = _securityService.SignPayload(
channel.TenantId,
channel.ChannelId,
payloadBytes,
timestamp);
request.Headers.Add("X-StellaOps-Signature", signature);
}
using var response = await _httpClient.SendAsync(request, cancellationToken).ConfigureAwait(false);
var statusCode = (int)response.StatusCode;