The backend half of the sweep RD-18 did for the front end. git blame holds the provenance and stays correct when the code moves; the comment names a closed ticket and tells the reader nothing the sentence around it does not. public/letter.css and LetterHtml.golden.html change together, because the renderer inlines the CSS and the golden file snapshots the result. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
73 lines
2.6 KiB
C#
73 lines
2.6 KiB
C#
using System.Net;
|
|
using System.Net.Http.Json;
|
|
using BigRegister.Api.Contracts;
|
|
using BigRegister.Api.Zgw;
|
|
using Microsoft.AspNetCore.Mvc.Testing;
|
|
|
|
namespace BigRegister.Tests;
|
|
|
|
/// The inbound Notificaties (NRC) webhook — auth accept/reject + the audit trail it
|
|
/// writes via AuthzAuditStore (no Principal exists for an NRC caller, so this doesn't go
|
|
/// through the Principal-shaped AuditAuthz helper the user-facing endpoints use).
|
|
public class NotificatieTests(TestWebApplicationFactory factory) : IClassFixture<TestWebApplicationFactory>
|
|
{
|
|
private readonly HttpClient _client = factory.CreateClient();
|
|
|
|
private static NotificatieDto Sample(string zaakUrl) => new(
|
|
Kanaal: "zaken",
|
|
HoofdObject: zaakUrl,
|
|
Resource: "zaak",
|
|
ResourceUrl: zaakUrl,
|
|
Actie: "update",
|
|
Aanmaakdatum: DateTimeOffset.UtcNow,
|
|
Kenmerken: null);
|
|
|
|
private async Task<HttpResponseMessage> Post(string? authorization, string zaakUrl)
|
|
{
|
|
var req = new HttpRequestMessage(HttpMethod.Post, "/api/v1/zgw/notificaties")
|
|
{
|
|
Content = JsonContent.Create(Sample(zaakUrl)),
|
|
};
|
|
if (authorization is not null) req.Headers.TryAddWithoutValidation("Authorization", authorization);
|
|
return await _client.SendAsync(req);
|
|
}
|
|
|
|
private async Task<List<AuthzAuditDto>> AuditLog()
|
|
{
|
|
var req = new HttpRequestMessage(HttpMethod.Get, "/api/v1/admin/audit");
|
|
req.Headers.Add("X-Role", "admin");
|
|
var res = await _client.SendAsync(req);
|
|
res.EnsureSuccessStatusCode();
|
|
return (await res.Content.ReadFromJsonAsync<List<AuthzAuditDto>>())!;
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Correct_shared_secret_is_accepted_and_recorded()
|
|
{
|
|
var zaak = $"https://open-zaak.example/zaken/api/v1/zaken/{Guid.NewGuid()}";
|
|
var res = await Post("test-nrc-secret", zaak);
|
|
|
|
Assert.Equal(HttpStatusCode.NoContent, res.StatusCode);
|
|
Assert.Contains(await AuditLog(), e =>
|
|
e.Action == "zgw:notificatie" && e.Resource == zaak && e.Decision == "allow" && e.Role == "nrc");
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Wrong_secret_is_rejected_and_recorded()
|
|
{
|
|
var zaak = $"https://open-zaak.example/zaken/api/v1/zaken/{Guid.NewGuid()}";
|
|
var res = await Post("not-the-secret", zaak);
|
|
|
|
Assert.Equal(HttpStatusCode.Unauthorized, res.StatusCode);
|
|
Assert.Contains(await AuditLog(), e =>
|
|
e.Action == "zgw:notificatie" && e.Resource == zaak && e.Decision == "deny");
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Missing_authorization_header_is_rejected()
|
|
{
|
|
var zaak = $"https://open-zaak.example/zaken/api/v1/zaken/{Guid.NewGuid()}";
|
|
Assert.Equal(HttpStatusCode.Unauthorized, (await Post(null, zaak)).StatusCode);
|
|
}
|
|
}
|