feat(openzaak): real notification delivery to the BFF webhook (WP-58)
OpenZaak doesn't serve the Notificaties API itself (it's a separate app, open-notificaties) — standing one up for a real abonnement would triple this harness for a benefit it doesn't need (exactly one subscriber, this repo's own BFF). Instead, an opt-in compose overlay adds a celery worker and points OpenZaak's NotificationsConfig straight at the BFF's webhook via a zgw_consumers Service; bootstrap-notificaties.sh configures it idempotently and verify-notificatie.sh proves a real write delivers to the BFF's audit trail end-to-end. Verified live: preflight proves the webhook's shared-secret gate both ways (204/401), a zaak PATCH triggers real celery delivery, and rerunning both scripts against an already-configured harness stays idempotent. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Executable
+63
@@ -0,0 +1,63 @@
|
||||
#!/usr/bin/env bash
|
||||
# WP-58 — proves the "real write -> real webhook delivery" round-trip end-to-end: PATCHes the
|
||||
# zaak bootstrap-catalogus.sh seeded (a notified ZRC resource), then polls the BFF's own audit
|
||||
# trail (WP-41) for the resulting `zgw:notificatie` row. Requires bootstrap-catalogus.sh and
|
||||
# bootstrap-notificaties.sh to have already run.
|
||||
set -euo pipefail
|
||||
cd "$(dirname "${BASH_SOURCE[0]}")"
|
||||
|
||||
[ -f seeded.env ] || { echo "seeded.env missing — run ./bootstrap-catalogus.sh first" >&2; exit 1; }
|
||||
# Not `source`d: seeded.env's ZAAKTYPE_LABEL value contains an unquoted space (fine for the
|
||||
# line-oriented C# reader it's written for, not valid as sourceable shell).
|
||||
ZAAK_URL=$(grep '^ZAAK_URL=' seeded.env | cut -d= -f2-)
|
||||
|
||||
BFF_BASE="${BFF_BASE:-http://localhost:5000}"
|
||||
CLIENT_ID="bigregister-test"
|
||||
SECRET="bigregister-test-secret"
|
||||
|
||||
b64url() { openssl base64 -A | tr '+/' '-_' | tr -d '='; }
|
||||
jwt() {
|
||||
local header='{"alg":"HS256","typ":"JWT"}'
|
||||
local payload
|
||||
payload=$(printf '{"iss":"%s","iat":%d,"client_id":"%s","user_id":"%s","user_representation":"%s"}' \
|
||||
"$CLIENT_ID" "$(date +%s)" "$CLIENT_ID" "$CLIENT_ID" "verify")
|
||||
local h p signing_input sig
|
||||
h=$(printf '%s' "$header" | b64url)
|
||||
p=$(printf '%s' "$payload" | b64url)
|
||||
signing_input="$h.$p"
|
||||
sig=$(printf '%s' "$signing_input" | openssl dgst -sha256 -hmac "$SECRET" -binary | b64url)
|
||||
printf '%s.%s' "$signing_input" "$sig"
|
||||
}
|
||||
|
||||
echo "Triggering a real write: PATCH $ZAAK_URL (bijwerken — WP-57 granted zaken.aanmaken"
|
||||
echo "for exactly ONE status, so a second status create 403s; a zaak update is the write this"
|
||||
echo "client's narrowed scope can repeat)..."
|
||||
response=$(curl -sS -X PATCH -H "Authorization: Bearer $(jwt)" -H 'Content-Type: application/json' \
|
||||
-H 'Content-Crs: EPSG:4326' -H 'Accept-Crs: EPSG:4326' \
|
||||
-d "$(printf '{"toelichting":"wp-58 verify %s"}' "$(date -u +%s)")" \
|
||||
-w $'\n%{http_code}' "$ZAAK_URL")
|
||||
http_code="${response##*$'\n'}"
|
||||
if [[ ! "$http_code" =~ ^2 ]]; then
|
||||
echo "FAILED: zaak PATCH -> $http_code: ${response%$'\n'*}" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo " updated"
|
||||
|
||||
echo "Waiting for the BFF's audit trail to show the delivered notification..."
|
||||
for _ in $(seq 1 30); do
|
||||
if curl -sS -H 'X-Role: admin' "$BFF_BASE/api/v1/admin/audit" \
|
||||
| python3 -c "
|
||||
import json, sys
|
||||
rows = json.load(sys.stdin)
|
||||
found = any(r['action'] == 'zgw:notificatie' and r['resource'] == '$ZAAK_URL' and r['decision'] == 'allow' for r in rows)
|
||||
sys.exit(0 if found else 1)
|
||||
"; then
|
||||
echo " delivered: found a zgw:notificatie/allow row for $ZAAK_URL"
|
||||
exit 0
|
||||
fi
|
||||
sleep 2
|
||||
done
|
||||
|
||||
echo "FAILED: no delivered notification for $ZAAK_URL after 60s. Diagnostics:" >&2
|
||||
docker compose -f docker-compose.openzaak.yml -f docker-compose.openzaak.notificaties.yml logs --tail=50 celery >&2
|
||||
exit 1
|
||||
Reference in New Issue
Block a user