Initial WebhookServer implementation
Add the .NET 8 solution scaffolded against PLAN.md. Three projects share WebhookServer.Core (models, auth, execution, storage, IPC, callbacks) and WebhookServer.Service hosts an embedded Kestrel listener plus the named-pipe admin server. WebhookServer.Gui is a thin MVVM client over the pipe. Includes 25 unit tests covering HMAC verification, bearer auth, IP allowlist parsing, arg-template rendering, DPAPI round-trip, and the encrypt-on-save config store. Install/uninstall PowerShell scripts default to LocalSystem and accept a domain user or gMSA via -ServiceAccount. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
using System.Runtime.InteropServices;
|
||||
using WebhookServer.Core.Models;
|
||||
using WebhookServer.Core.Storage;
|
||||
using Xunit;
|
||||
|
||||
namespace WebhookServer.Core.Tests;
|
||||
|
||||
public class ConfigStoreTests
|
||||
{
|
||||
[Fact]
|
||||
public async Task Save_then_load_preserves_endpoints_and_encrypts_secrets()
|
||||
{
|
||||
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) return;
|
||||
|
||||
var path = Path.Combine(Path.GetTempPath(), $"webhook-test-{Guid.NewGuid():N}.json");
|
||||
try
|
||||
{
|
||||
var store = new ConfigStore(path);
|
||||
var cfg = new ServerConfig
|
||||
{
|
||||
HttpPort = 9000,
|
||||
Endpoints =
|
||||
{
|
||||
new EndpointConfig
|
||||
{
|
||||
Slug = "deploy",
|
||||
AuthMode = AuthMode.Bearer,
|
||||
Bearer = new BearerOptions { Secret = ProtectedString.FromPlaintext("topsecret") },
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
await store.SaveAsync(cfg);
|
||||
|
||||
// Persisted config must not contain plaintext.
|
||||
var rawJson = await File.ReadAllTextAsync(path);
|
||||
Assert.DoesNotContain("topsecret", rawJson);
|
||||
Assert.Contains("encrypted", rawJson);
|
||||
|
||||
var reloaded = await store.LoadAsync();
|
||||
ConfigStore.DecryptSecrets(reloaded);
|
||||
|
||||
var ep = Assert.Single(reloaded.Endpoints);
|
||||
Assert.Equal("deploy", ep.Slug);
|
||||
Assert.Equal("topsecret", ep.Bearer!.Secret.Plaintext);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (File.Exists(path)) File.Delete(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user