On the single self-hosted runner CI jobs run sequentially, so booting OpenZaak once beats once-per-job. Replace the integration + notifications + compose-smoke jobs with one verify-stack job that brings the full stack up once and runs, as clearly-named steps: health (make verify-up, the DoD smoke) → ACL ↔ OpenZaak (verify-acl) → OpenZaak → NRC delivery (verify-nrc) → teardown (always) + log dump on failure. The check logic moves into stack-agnostic runners (run-acl-integration.sh, run-notification-check.sh) that operate on whatever stack is already up, reaching services by container IP. The local single-concern wrappers (make integration oz-only, make verify-notifications oz+nrc) keep working by delegating to the same runners, so nothing is duplicated. make ci now runs the consolidated 'verify' stage. Verified locally: make verify boots the full stack once, ACL integration passes and the NRC notification is delivered, then tears down. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -63,47 +63,27 @@ jobs:
|
||||
path: services/acl/StrykerOutput/**/reports/mutation-report.html
|
||||
if-no-files-found: warn
|
||||
|
||||
integration:
|
||||
# One stage for every check that needs the live stack. On the single self-hosted
|
||||
# runner jobs run sequentially, so booting OpenZaak once (instead of once per job)
|
||||
# is the cheapest layout (issue #58). No setup-dotnet: the ACL test runs in a built
|
||||
# image and everything reaches services by container IP. Needs Docker + egress
|
||||
# (base images, nuget, selectielijst.openzaak.nl).
|
||||
verify-stack:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: https://github.com/actions/checkout@v4
|
||||
# No setup-dotnet: `make integration` runs the seed and the test as containers
|
||||
# *inside* the OpenZaak compose network (reaching it by container IP), so dotnet
|
||||
# lives in the test image and the runner needs only Docker. This sidesteps the
|
||||
# runner being unable to reach published ports (gitea-actions-gotchas.md §5).
|
||||
# Needs egress to pull base images + nuget + selectielijst.openzaak.nl.
|
||||
- run: make integration
|
||||
- name: dump OpenZaak logs on failure
|
||||
# Bring the full stack up + wait for health — this also is the DoD "compose up
|
||||
# reaches green health" smoke (it replaces the old compose-smoke job).
|
||||
- name: Bring up the full stack & wait for health
|
||||
run: make verify-up
|
||||
- name: ACL ↔ OpenZaak integration tests
|
||||
run: make verify-acl
|
||||
- name: OpenZaak → NRC notification delivery
|
||||
run: make verify-nrc
|
||||
# Log dump must precede teardown (which removes the containers).
|
||||
- name: Dump container logs on failure
|
||||
if: failure()
|
||||
run: docker compose -f infra/openzaak/docker-compose.yml logs --no-color --tail=80 oz-init openzaak 2>&1 || true
|
||||
- name: tear down on failure
|
||||
if: failure()
|
||||
run: docker compose -f infra/openzaak/docker-compose.yml down --volumes 2>&1 || true
|
||||
|
||||
notifications:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: https://github.com/actions/checkout@v4
|
||||
# `make verify-notifications` brings up OpenZaak + NRC, seeds, and asserts a
|
||||
# zaak-create notification is delivered to a subscriber — all via containers on
|
||||
# the compose network (the runner can't reach published ports; §5). Needs only
|
||||
# Docker + egress (base images, selectielijst.openzaak.nl).
|
||||
- run: make verify-notifications
|
||||
- name: dump OpenZaak/NRC logs on failure
|
||||
if: failure()
|
||||
run: docker compose -f infra/openzaak/docker-compose.yml -f infra/opennotificaties/docker-compose.yml logs --no-color --tail=100 oz-init openzaak nrc-init nrc-web nrc-celery nrc-beat 2>&1 || true
|
||||
- name: tear down on failure
|
||||
if: failure()
|
||||
run: docker compose -f infra/openzaak/docker-compose.yml -f infra/opennotificaties/docker-compose.yml down --volumes 2>&1 || true
|
||||
|
||||
compose-smoke:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: https://github.com/actions/checkout@v4
|
||||
- run: make smoke
|
||||
- name: dump container logs on failure
|
||||
if: failure()
|
||||
run: docker compose -f infra/docker-compose.yml logs --no-color --tail=80 oz-init openzaak nrc-init nrc-web flowable-init keycloak acl bff 2>&1 || true
|
||||
- name: tear down on failure
|
||||
if: failure()
|
||||
run: docker compose -f infra/docker-compose.yml down --volumes 2>&1 || true
|
||||
run: docker compose -f infra/docker-compose.yml logs --no-color --tail=100 oz-init openzaak nrc-init nrc-web nrc-celery nrc-beat flowable-init keycloak acl bff 2>&1 || true
|
||||
- name: Tear down
|
||||
if: always()
|
||||
run: make down
|
||||
|
||||
58
Makefile
58
Makefile
@@ -43,10 +43,11 @@ export DOCKER_HOST := unix://$(PODMAN_SOCK)
|
||||
endif
|
||||
endif
|
||||
|
||||
.PHONY: ci lint build unit mutation integration verify-notifications smoke up down local local-down changelog openzaak-up openzaak-smoke openzaak-seed openzaak-down stack-up stack-smoke stack-down keycloak-up keycloak-smoke keycloak-down flowable-up flowable-smoke flowable-down help
|
||||
.PHONY: ci lint build unit mutation integration verify verify-up verify-acl verify-nrc verify-notifications smoke up down local local-down changelog openzaak-up openzaak-smoke openzaak-seed openzaak-down stack-up stack-smoke stack-down keycloak-up keycloak-smoke keycloak-down flowable-up flowable-smoke flowable-down help
|
||||
|
||||
## ci: run the full pipeline — lint, build, unit, mutation, smoke (mirrors Gitea Actions)
|
||||
ci: lint build unit mutation smoke
|
||||
## ci: run the full pipeline — lint, build, unit, mutation, verify (mirrors Gitea Actions)
|
||||
## `verify` is the live-stack stage (full stack up once → ACL + notification checks).
|
||||
ci: lint build unit mutation verify
|
||||
|
||||
## lint: verify formatting (no changes)
|
||||
lint:
|
||||
@@ -106,12 +107,45 @@ local-down:
|
||||
changelog:
|
||||
git-cliff --output CHANGELOG.md
|
||||
|
||||
## integration: ACL integration tests against a real OpenZaak (S-04a, #46). The
|
||||
## seed and the test run inside the compose network (reaching http://openzaak:8000),
|
||||
## so this works on the hosted CI runner where a runner process can't reach the
|
||||
## stack's published ports. Brings the stack up, seeds a PUBLISHED BIG zaaktype,
|
||||
## runs the Integration-category tests, then always tears down. Kept out of
|
||||
## `unit`/`mutation` because it needs the live stack. See infra/run-integration.sh + ADR-0006.
|
||||
# ── ZGW verification ───────────────────────────────────────────────────────
|
||||
# On the single runner CI jobs run sequentially, so the OpenZaak-dependent checks
|
||||
# share ONE full-stack bring-up: the `verify-stack` CI job runs `verify-up` then
|
||||
# `verify-acl` + `verify-nrc` as steps against the same stack (issue #58). The
|
||||
# check logic lives in stack-agnostic runners that reach services by container IP
|
||||
# (gitea-actions-gotchas.md §5/§6); `integration` / `verify-notifications` are local
|
||||
# convenience wrappers that bring up a lighter stack and call the same runners.
|
||||
|
||||
## verify-up: bring the FULL stack up and wait for health (CI verify-stack step 1;
|
||||
## subsumes the old compose-smoke health gate — the DoD "up reaches green" check).
|
||||
verify-up:
|
||||
$(SEED) oz nrc kc fl
|
||||
docker compose -f $(COMPOSE) up -d --build
|
||||
WAIT_TIMEOUT=420 bash infra/wait-healthy.sh $(WAIT_SVCS)
|
||||
|
||||
## verify-acl: ACL ↔ OpenZaak integration tests against the already-running stack.
|
||||
verify-acl:
|
||||
bash infra/run-acl-integration.sh
|
||||
|
||||
## verify-nrc: OpenZaak → NRC notification delivery against the already-running stack.
|
||||
verify-nrc:
|
||||
bash infra/run-notification-check.sh
|
||||
|
||||
## verify: local mirror of the CI verify-stack job — full stack up once, both checks,
|
||||
## tear down (always). For fast single-concern local iteration use `integration`
|
||||
## (oz-only) or `verify-notifications` (oz+nrc) instead.
|
||||
verify:
|
||||
$(SEED) oz nrc kc fl
|
||||
docker compose -f $(COMPOSE) up -d --build
|
||||
@bash -c 'set -e; rc=0; \
|
||||
WAIT_TIMEOUT=420 bash infra/wait-healthy.sh $(WAIT_SVCS) \
|
||||
&& bash infra/run-acl-integration.sh \
|
||||
&& bash infra/run-notification-check.sh || rc=$$?; \
|
||||
docker compose -f $(COMPOSE) down --volumes >/dev/null 2>&1; \
|
||||
docker volume rm -f $(CFG_VOLS) >/dev/null 2>&1; \
|
||||
exit $$rc'
|
||||
|
||||
## integration: local convenience — ACL integration test against a throwaway
|
||||
## OpenZaak-only stack (fast iteration). CI uses verify-acl on the shared stack.
|
||||
integration:
|
||||
bash infra/run-integration.sh
|
||||
|
||||
@@ -147,10 +181,8 @@ openzaak-down:
|
||||
docker compose -f $(OZ_COMPOSE) down --volumes
|
||||
-docker volume rm -f rr-oz-config
|
||||
|
||||
## verify-notifications: end-to-end check that a zaak created in OpenZaak is
|
||||
## published to NRC and delivered to a subscriber (S-01-c). Brings the stack up,
|
||||
## seeds, drives a zaak + sink abonnement inside the network, asserts delivery,
|
||||
## tears down. Runner-safe (no host-port access). See infra/verify-notifications.sh.
|
||||
## verify-notifications: local convenience — OpenZaak → NRC notification delivery
|
||||
## against a throwaway oz+nrc stack (S-01-c). CI uses verify-nrc on the shared stack.
|
||||
verify-notifications:
|
||||
bash infra/verify-notifications.sh
|
||||
|
||||
|
||||
@@ -46,10 +46,11 @@ itself. No new test dependency is added.**
|
||||
`OpenZaakGateway` against it.
|
||||
- **The lane is kept out of the fast checks.** `make unit` runs with
|
||||
`--filter "Category!=Integration"`; Stryker is pinned to `Acl.Tests` (`test-projects`), so
|
||||
neither the unit nor the mutation lane needs a live stack. A new `make integration` target
|
||||
(`infra/run-integration.sh`) brings the stack up, seeds, runs the lane, and always tears down
|
||||
— mirrored by a Gitea Actions `integration` job. This matches `make` being the single source
|
||||
of truth (ADR-0005).
|
||||
neither the unit nor the mutation lane needs a live stack. A `make integration` target
|
||||
(`infra/run-integration.sh`) brings up a throwaway OpenZaak and runs the lane locally.
|
||||
In CI the check runs as the `verify-acl` step of the consolidated `verify-stack` job
|
||||
(issue #58) — one shared full-stack bring-up. This matches `make` being the single
|
||||
source of truth (ADR-0005).
|
||||
- **Publishing is opt-in in the seed.** `infra/openzaak/seed_catalogus.py` gains an
|
||||
`OZ_PUBLISH=1` path that adds the relations OpenZaak's publish requires — two statustypen
|
||||
(begin/eind), a roltype, and a resultaattype whose Selectielijst procestype is matched onto
|
||||
|
||||
@@ -41,11 +41,12 @@ existing `big-reference-seed` client, and run NRC's celery-beat so deliveries ha
|
||||
S-01 stack dropped beat — so notifications were accepted but never delivered. An
|
||||
`nrc-beat` service is added to every compose; the interval is lowered to 5s.
|
||||
|
||||
Verification is a runner-safe smoke (`make verify-notifications`,
|
||||
`infra/verify-notifications.sh` + a `notifications` CI job): it brings the stack up,
|
||||
seeds a published BIG zaaktype, registers an abonnement to a webhook sink, creates a
|
||||
zaak, and asserts the sink receives the `zaken`/`create` notification — all from
|
||||
containers **inside** the compose network (ADR-0006).
|
||||
Verification is a runner-safe smoke (`infra/run-notification-check.sh`): it seeds a
|
||||
published BIG zaaktype, registers an abonnement to a webhook sink, creates a zaak, and
|
||||
asserts the sink receives the `zaken`/`create` notification — all from containers
|
||||
**inside** the compose network (ADR-0006). Locally it runs via `make verify-notifications`
|
||||
(a throwaway oz+nrc stack); in CI it runs as the `verify-nrc` step of the consolidated
|
||||
`verify-stack` job (one shared full-stack bring-up — issue #58).
|
||||
|
||||
## Consequences
|
||||
|
||||
|
||||
@@ -17,20 +17,21 @@ and CI cannot drift:
|
||||
| `build` | `make build` → `dotnet build … -c Release` | .NET 10 SDK |
|
||||
| `unit` | `make unit` → `dotnet test … -c Release --filter "Category!=Integration"` | .NET 10 SDK |
|
||||
| `mutation` | `make mutation` → `dotnet tool restore` → `dotnet stryker` (ACL); uploads the HTML report as an artifact | .NET 10 SDK |
|
||||
| `integration` | `make integration` → `infra/run-integration.sh`: OpenZaak up → seed a **published** BIG zaaktype + run `Acl.IntegrationTests` **as containers inside the compose network** → tear down | container engine + egress (base images, nuget, `selectielijst.openzaak.nl`) |
|
||||
| `notifications` | `make verify-notifications` → bring up OpenZaak + NRC → seed → assert a zaak-create notification reaches a subscriber (containers on the network) → tear down | container engine + egress (base images, `selectielijst.openzaak.nl`) |
|
||||
| `compose-smoke` | `make smoke` → seed config volumes → `up -d` (full stack) → `up --wait` durable services → `down` | container engine + compose v2 |
|
||||
| `verify-stack` | the single live-stack stage — steps: `make verify-up` (full stack up + health, the DoD smoke) → `make verify-acl` (ACL ↔ OpenZaak) → `make verify-nrc` (OpenZaak → NRC delivery) → `make down` | container engine + egress (base images, nuget, `selectielijst.openzaak.nl`) |
|
||||
|
||||
> **The `integration` job needs no `setup-dotnet`.** dotnet runs inside the test
|
||||
> image, and both the seed and the test join the OpenZaak network and reach it by
|
||||
> container IP — so the runner never has to reach a published port
|
||||
> (see [gitea-actions-gotchas.md §5](gitea-actions-gotchas.md)).
|
||||
> **Why one `verify-stack` job, not three.** The single self-hosted runner runs jobs
|
||||
> **sequentially**, so booting OpenZaak once (instead of once per check) is the
|
||||
> cheapest layout (issue #58). It subsumes the old `integration`, `notifications`, and
|
||||
> `compose-smoke` jobs — the bring-up step *is* the "compose up reaches green health"
|
||||
> gate. No `setup-dotnet`: the ACL test runs in a built image and every check reaches
|
||||
> services by **container IP** (the runner can't reach published ports — see
|
||||
> [gitea-actions-gotchas.md §5/§6](gitea-actions-gotchas.md)).
|
||||
|
||||
All `uses:` references are absolute, tag-pinned URLs (`https://github.com/actions/checkout@v4`,
|
||||
`https://github.com/actions/setup-dotnet@v4`) per CLAUDE.md §8.7 and §15 — Gitea
|
||||
Actions resolves them from GitHub.
|
||||
|
||||
> **`compose-smoke` runs on a containerized runner.** Workspace bind mounts do
|
||||
> **`verify-stack` runs on a containerized runner.** Workspace bind mounts do
|
||||
> **not** reach the sibling containers Compose starts, so config/assets are
|
||||
> streamed into external named volumes via `docker cp` (`infra/seed-config.sh`),
|
||||
> and the upstream images are used verbatim (no build). If you add a service that
|
||||
@@ -92,19 +93,23 @@ the containerized CI runner). Keep the two files in sync.
|
||||
|
||||
## Running CI locally (`make ci`)
|
||||
|
||||
Until the runner exists, run the full pipeline yourself before pushing:
|
||||
`make ci` runs the exact same checks as the pipeline — handy to run before pushing:
|
||||
|
||||
```bash
|
||||
make ci # lint + build + unit + mutation + smoke — the fast pipeline lanes
|
||||
make ci # lint + build + unit + mutation + verify — mirrors the pipeline
|
||||
make lint # or a single stage
|
||||
make mutation # Stryker.NET ratchet on the ACL
|
||||
make smoke # compose up --wait, curl /health, tear down
|
||||
make integration # ACL ↔ real OpenZaak (its own CI job; not part of `make ci`)
|
||||
make verify # the live-stack stage: full stack up once → ACL + NRC checks → down
|
||||
```
|
||||
|
||||
> `make integration` is a separate, heavier lane (it stands the OpenZaak stack up and
|
||||
> seeds a published zaaktype), so it is **not** folded into `make ci`. Run it before
|
||||
> pushing changes that touch the ACL gateway or the OpenZaak seed. See ADR-0006.
|
||||
> **`make verify`** mirrors the CI `verify-stack` job: it boots the full stack once and
|
||||
> runs both the ACL ↔ OpenZaak and OpenZaak → NRC checks against it. For fast,
|
||||
> single-concern local iteration use a lighter throwaway stack instead:
|
||||
>
|
||||
> ```bash
|
||||
> make integration # ACL ↔ OpenZaak only (no NRC)
|
||||
> make verify-notifications # OpenZaak → NRC delivery only
|
||||
> ```
|
||||
|
||||
**Prerequisites:** .NET 10 SDK, a container engine with Compose v2, and `curl`.
|
||||
|
||||
|
||||
@@ -173,7 +173,7 @@ reality is a service name or an IPv4 literal — and only the IP passes.
|
||||
**Fix** — in-network tooling reaches OpenZaak/NRC by **container IP**
|
||||
(`docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}'`), not
|
||||
service name; the notif verify harness also registers the sink callback by IP.
|
||||
(`infra/run-integration.sh`, `infra/verify-notifications.sh`.)
|
||||
(`infra/run-acl-integration.sh`, `infra/run-notification-check.sh`.)
|
||||
|
||||
**Related — abonnement callbacks must enforce auth.** NRC probes a callback when an
|
||||
abonnement is registered and refuses it (`no-auth-on-callback-url`) unless it returns
|
||||
|
||||
37
infra/run-acl-integration.sh
Executable file
37
infra/run-acl-integration.sh
Executable file
@@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Run the ACL integration tests (Category=Integration) against the OpenZaak that is
|
||||
# ALREADY running — works for any stack: oz-only (`make integration`), the standalone
|
||||
# oz+nrc stack, or the full compose stack (the CI `verify-stack` job). Seeds a
|
||||
# published BIG zaaktype (idempotent), then builds + runs the test image on the stack
|
||||
# network, reaching OpenZaak by container IP (a single-label host isn't URL-valid;
|
||||
# the runner can't reach published ports — see gitea-actions-gotchas.md §5/§6).
|
||||
#
|
||||
# Does NOT manage the stack lifecycle: the caller owns bring-up + teardown. Plain
|
||||
# docker primitives only (docker/podman-portable). See ADR-0006.
|
||||
set -euo pipefail
|
||||
|
||||
here="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
root="$(cd "$here/.." && pwd)"
|
||||
|
||||
# The OpenZaak API container, matched across compose projects + docker/podman naming
|
||||
# (`<project>[-_]openzaak[-_]<n>`); the delimiters exclude oz-db / oz-redis / oz-init.
|
||||
oz="$(docker ps -q --filter 'name=[-_]openzaak[-_]' | head -1)"
|
||||
[ -n "$oz" ] || { echo "ERROR: no running OpenZaak container found — bring the stack up first" >&2; exit 1; }
|
||||
net="$(docker inspect -f '{{range $k,$_ := .NetworkSettings.Networks}}{{$k}}{{"\n"}}{{end}}' "$oz" | head -1)"
|
||||
oz_ip="$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$oz")"
|
||||
oz_base="http://$oz_ip:8000"
|
||||
echo ">> OpenZaak at $oz_base on network $net"
|
||||
|
||||
echo ">> seeding a published BIG zaaktype (idempotent)"
|
||||
sid="$(docker create --network "$net" -e "OZ_BASE=$oz_base" -e OZ_PUBLISH=1 \
|
||||
python:3-slim python /seed.py)"
|
||||
docker cp "$here/openzaak/seed_catalogus.py" "$sid:/seed.py" >/dev/null
|
||||
docker start -a "$sid"
|
||||
docker rm -f "$sid" >/dev/null
|
||||
|
||||
echo ">> building the integration test image"
|
||||
docker build -f "$root/services/acl/Dockerfile.integration" -t rr-acl-integration "$root/services/acl"
|
||||
|
||||
echo ">> running the ACL integration tests (inside the network)"
|
||||
docker run --rm --network "$net" -e "OZ_BASE=$oz_base" rr-acl-integration
|
||||
@@ -1,21 +1,14 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Run the ACL ↔ real-OpenZaak integration test (S-04a / #46) end to end.
|
||||
# Local convenience: run the ACL integration test against a throwaway OpenZaak-only
|
||||
# stack (fast iteration on the ACL gateway). Brings OpenZaak up, runs the shared
|
||||
# stack-agnostic check (infra/run-acl-integration.sh), then always tears down.
|
||||
#
|
||||
# Everything that talks to OpenZaak runs *inside* the compose network and reaches
|
||||
# it by service name (http://openzaak:8000) — the hosted CI runner can't reach the
|
||||
# stack's published ports (sibling containers) and bind mounts don't reach the
|
||||
# daemon either (gitea-actions-gotchas.md §1/§5). So we use only plain docker
|
||||
# primitives (run / create / cp / build) — portable across docker compose (CI) and
|
||||
# podman-compose (local), exactly like infra/seed-config.sh. See ADR-0006.
|
||||
#
|
||||
# Steps: bring OpenZaak up → wait for it healthy → seed a PUBLISHED BIG zaaktype
|
||||
# (a seed container on the network) → build + run the test container on the network
|
||||
# → always tear down.
|
||||
# CI does not use this — there the full stack is brought up once and the same runner
|
||||
# is invoked as a step (see the `verify-stack` job / Makefile `verify-*`). See ADR-0006.
|
||||
set -euo pipefail
|
||||
|
||||
here="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
root="$(cd "$here/.." && pwd)"
|
||||
OZ_COMPOSE="$here/openzaak/docker-compose.yml"
|
||||
|
||||
cleanup() {
|
||||
@@ -29,40 +22,13 @@ bash "$here/seed-config.sh" oz
|
||||
docker compose -f "$OZ_COMPOSE" up -d
|
||||
|
||||
echo ">> waiting for the OpenZaak API container to be healthy"
|
||||
# Match the API container under both docker compose (openzaak-openzaak-1) and
|
||||
# podman-compose (openzaak_openzaak_1) naming; the regex excludes oz-db / oz-redis.
|
||||
api=""
|
||||
for _ in $(seq 1 140); do
|
||||
api="$(docker ps -q --filter 'name=openzaak[-_]openzaak' | head -1)"
|
||||
if [ -n "$api" ]; then
|
||||
status="$(docker inspect -f '{{if .State.Health}}{{.State.Health.Status}}{{end}}' "$api" 2>/dev/null || true)"
|
||||
[ "$status" = "healthy" ] && break
|
||||
oz="$(docker ps -q --filter 'name=[-_]openzaak[-_]' | head -1)"
|
||||
if [ -n "$oz" ] && [ "$(docker inspect -f '{{if .State.Health}}{{.State.Health.Status}}{{end}}' "$oz" 2>/dev/null || true)" = healthy ]; then
|
||||
break
|
||||
fi
|
||||
sleep 3
|
||||
done
|
||||
[ -n "$api" ] || { echo "ERROR: OpenZaak API container never appeared" >&2; exit 1; }
|
||||
[ "${status:-}" = "healthy" ] || { echo "ERROR: OpenZaak not healthy (status=${status:-none})" >&2; exit 1; }
|
||||
[ -n "${oz:-}" ] || { echo "ERROR: OpenZaak never came up" >&2; exit 1; }
|
||||
|
||||
# The network the API container is attached to — joined by the seed + test below.
|
||||
net="$(docker inspect -f '{{range $k,$_ := .NetworkSettings.Networks}}{{$k}}{{"\n"}}{{end}}' "$api" | head -1)"
|
||||
# Reach OpenZaak by container IP, not by the service name. OpenZaak echoes its
|
||||
# request Host into the self-referential URLs it returns, then validates those URLs
|
||||
# with Django's URLValidator — which rejects a single-label host like `openzaak`
|
||||
# ("Voer een geldige URL in") while accepting an IPv4 literal (and `localhost`).
|
||||
oz_ip="$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$api")"
|
||||
oz_base="http://${oz_ip}:8000"
|
||||
echo ">> OpenZaak healthy on network $net at $oz_base"
|
||||
|
||||
echo ">> seeding a published BIG zaaktype (OZ_PUBLISH=1, inside the network)"
|
||||
sid="$(docker create --network "$net" \
|
||||
-e "OZ_BASE=$oz_base" -e OZ_PUBLISH=1 \
|
||||
python:3-slim python /seed_catalogus.py)"
|
||||
docker cp "$here/openzaak/seed_catalogus.py" "$sid:/seed_catalogus.py"
|
||||
docker start -a "$sid"
|
||||
docker rm -f "$sid" >/dev/null
|
||||
|
||||
echo ">> building the integration test image"
|
||||
docker build -f "$root/services/acl/Dockerfile.integration" -t rr-acl-integration "$root/services/acl"
|
||||
|
||||
echo ">> running the integration tests (inside the network)"
|
||||
docker run --rm --network "$net" -e "OZ_BASE=$oz_base" rr-acl-integration
|
||||
bash "$here/run-acl-integration.sh"
|
||||
|
||||
72
infra/run-notification-check.sh
Executable file
72
infra/run-notification-check.sh
Executable file
@@ -0,0 +1,72 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Verify the OpenZaak → NRC notification path against an ALREADY-RUNNING oz+nrc stack
|
||||
# (the standalone stack via `make verify-notifications`, or the full compose stack in
|
||||
# the CI `verify-stack` job). Seeds a published BIG zaaktype (idempotent), registers
|
||||
# an abonnement to a webhook sink, creates a zaak, and asserts the sink receives the
|
||||
# `zaken`/`create` notification. All in-network, reaching services by container IP
|
||||
# (single-label hosts aren't URL-valid; the runner can't reach published ports).
|
||||
#
|
||||
# Does NOT manage the stack lifecycle (the caller owns bring-up + teardown), but it
|
||||
# cleans up the throwaway sink/driver it creates. Plain docker primitives only.
|
||||
# See ADR-0007.
|
||||
set -euo pipefail
|
||||
|
||||
here="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
SINK_AUTH="Bearer notification-sink-token"
|
||||
|
||||
cleanup() { docker rm -f rr-nsink rr-nverify >/dev/null 2>&1 || true; }
|
||||
trap cleanup EXIT
|
||||
|
||||
ip() { docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$1"; }
|
||||
|
||||
oz="$(docker ps -q --filter 'name=[-_]openzaak[-_]' | head -1)"
|
||||
nrc="$(docker ps -q --filter 'name=nrc-web' | head -1)"
|
||||
[ -n "$oz" ] && [ -n "$nrc" ] || { echo "ERROR: OpenZaak and/or NRC not running — bring the stack up first" >&2; exit 1; }
|
||||
net="$(docker inspect -f '{{range $k,$_ := .NetworkSettings.Networks}}{{$k}}{{"\n"}}{{end}}' "$oz" | head -1)"
|
||||
oz_ip="$(ip "$oz")"; nrc_ip="$(ip "$nrc")"
|
||||
echo ">> network=$net openzaak=$oz_ip nrc=$nrc_ip"
|
||||
|
||||
echo ">> seeding a published BIG zaaktype (idempotent)"
|
||||
sid="$(docker create --network "$net" -e "OZ_BASE=http://$oz_ip:8000" -e OZ_PUBLISH=1 \
|
||||
python:3-slim python /seed.py)"
|
||||
docker cp "$here/openzaak/seed_catalogus.py" "$sid:/seed.py" >/dev/null
|
||||
docker start -a "$sid"
|
||||
docker rm -f "$sid" >/dev/null
|
||||
|
||||
echo ">> starting the webhook sink"
|
||||
docker rm -f rr-nsink >/dev/null 2>&1 || true
|
||||
sink="$(docker create --network "$net" --name rr-nsink -e "EXPECTED_AUTH=$SINK_AUTH" \
|
||||
python:3-slim python /sink.py)"
|
||||
docker cp "$here/notification-sink.py" "$sink:/sink.py" >/dev/null
|
||||
docker start "$sink" >/dev/null
|
||||
sleep 1
|
||||
sink_ip="$(ip rr-nsink)"
|
||||
echo ">> sink at $sink_ip:9000"
|
||||
|
||||
echo ">> registering abonnement + creating a zaak"
|
||||
docker rm -f rr-nverify >/dev/null 2>&1 || true
|
||||
drv="$(docker create --network "$net" --name rr-nverify \
|
||||
-e "OZ_BASE=http://$oz_ip:8000" -e "NRC_BASE=http://$nrc_ip:8000" \
|
||||
-e "SINK_CALLBACK=http://$sink_ip:9000/" -e "SINK_AUTH=$SINK_AUTH" \
|
||||
python:3-slim python /driver.py)"
|
||||
docker cp "$here/verify-notification-driver.py" "$drv:/driver.py" >/dev/null
|
||||
docker start -a "$drv"
|
||||
zaak_url="$(docker logs rr-nverify 2>/dev/null | sed -n 's/^ZAAK_CREATED //p' | head -1)"
|
||||
docker rm -f rr-nverify >/dev/null
|
||||
[ -n "$zaak_url" ] || { echo "ERROR: driver did not create a zaak" >&2; exit 1; }
|
||||
zaak_uuid="${zaak_url##*/}"
|
||||
echo ">> zaak created: $zaak_url"
|
||||
|
||||
echo ">> waiting for the notification to reach the sink"
|
||||
for _ in $(seq 1 30); do
|
||||
if docker logs rr-nsink 2>&1 | grep -q "$zaak_uuid"; then
|
||||
echo "OK — NRC delivered the zaken notification for zaak $zaak_uuid to the sink"
|
||||
docker logs rr-nsink 2>&1 | grep "$zaak_uuid" | tail -1 | cut -c1-300
|
||||
exit 0
|
||||
fi
|
||||
sleep 2
|
||||
done
|
||||
echo "FAIL — the sink never received a notification for zaak $zaak_uuid" >&2
|
||||
echo "--- sink log ---" >&2; docker logs rr-nsink 2>&1 | tail -8 >&2
|
||||
exit 1
|
||||
@@ -1,36 +1,29 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Verify the OpenZaak → Open Notificaties (NRC) notification path end to end (S-01-c,
|
||||
# #56): a zaak created in OpenZaak is published to NRC and delivered to a subscriber.
|
||||
# Local convenience: verify the OpenZaak → NRC notification path against a throwaway
|
||||
# oz+nrc stack. Brings both up (notifications enabled), runs the shared stack-agnostic
|
||||
# check (infra/run-notification-check.sh), then always tears down.
|
||||
#
|
||||
# Everything that talks to OpenZaak/NRC runs *inside* the compose network and reaches
|
||||
# them by container IP — the hosted CI runner can't reach published ports (sibling
|
||||
# containers, gitea-actions-gotchas.md §5) and OpenZaak/NRC reject a single-label host
|
||||
# in URLs (Django URLValidator). Plain docker primitives only (docker/podman-portable),
|
||||
# like infra/seed-config.sh and infra/run-integration.sh. See ADR-0007.
|
||||
# CI does not use this — there the full stack is brought up once and the same runner
|
||||
# is invoked as a step (see the `verify-stack` job / Makefile `verify-*`). See ADR-0007.
|
||||
set -euo pipefail
|
||||
|
||||
here="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
OZ_COMPOSE="$here/openzaak/docker-compose.yml"
|
||||
NRC_COMPOSE="$here/opennotificaties/docker-compose.yml"
|
||||
SINK_AUTH="Bearer notification-sink-token"
|
||||
|
||||
cleanup() {
|
||||
docker rm -f rr-nsink rr-nverify >/dev/null 2>&1 || true
|
||||
docker compose -f "$OZ_COMPOSE" -f "$NRC_COMPOSE" down --volumes >/dev/null 2>&1 || true
|
||||
docker volume rm -f rr-oz-config rr-nrc-config >/dev/null 2>&1 || true
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
ip() { docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$1"; }
|
||||
|
||||
wait_healthy() { # name-regex -> echoes container id
|
||||
local re="$1" cid status
|
||||
wait_healthy() { # name-regex
|
||||
local re="$1" cid
|
||||
for _ in $(seq 1 140); do
|
||||
cid="$(docker ps -q --filter "name=$re" | head -1)"
|
||||
if [ -n "$cid" ]; then
|
||||
status="$(docker inspect -f '{{if .State.Health}}{{.State.Health.Status}}{{end}}' "$cid" 2>/dev/null || true)"
|
||||
[ "$status" = healthy ] && { echo "$cid"; return 0; }
|
||||
if [ -n "$cid" ] && [ "$(docker inspect -f '{{if .State.Health}}{{.State.Health.Status}}{{end}}' "$cid" 2>/dev/null || true)" = healthy ]; then
|
||||
return 0
|
||||
fi
|
||||
sleep 3
|
||||
done
|
||||
@@ -42,52 +35,7 @@ bash "$here/seed-config.sh" oz nrc
|
||||
OZ_NOTIFICATIONS_DISABLED=false docker compose -f "$OZ_COMPOSE" -f "$NRC_COMPOSE" up -d
|
||||
|
||||
echo ">> waiting for OpenZaak + NRC to be healthy"
|
||||
oz="$(wait_healthy 'openzaak[-_]openzaak')" || { echo "ERROR: OpenZaak not healthy" >&2; exit 1; }
|
||||
nrc="$(wait_healthy 'nrc-web')" || { echo "ERROR: NRC not healthy" >&2; exit 1; }
|
||||
net="$(docker inspect -f '{{range $k,$_ := .NetworkSettings.Networks}}{{$k}}{{"\n"}}{{end}}' "$oz" | head -1)"
|
||||
oz_ip="$(ip "$oz")"; nrc_ip="$(ip "$nrc")"
|
||||
echo ">> network=$net openzaak=$oz_ip nrc=$nrc_ip"
|
||||
wait_healthy '[-_]openzaak[-_]' || { echo "ERROR: OpenZaak not healthy" >&2; exit 1; }
|
||||
wait_healthy 'nrc-web' || { echo "ERROR: NRC not healthy" >&2; exit 1; }
|
||||
|
||||
echo ">> seeding a published BIG zaaktype"
|
||||
sid="$(docker create --network "$net" -e "OZ_BASE=http://$oz_ip:8000" -e OZ_PUBLISH=1 \
|
||||
python:3-slim python /seed.py)"
|
||||
docker cp "$here/openzaak/seed_catalogus.py" "$sid:/seed.py" >/dev/null
|
||||
docker start -a "$sid"
|
||||
docker rm -f "$sid" >/dev/null
|
||||
|
||||
echo ">> starting the webhook sink"
|
||||
docker rm -f rr-nsink >/dev/null 2>&1 || true
|
||||
sink="$(docker create --network "$net" --name rr-nsink -e "EXPECTED_AUTH=$SINK_AUTH" \
|
||||
python:3-slim python /sink.py)"
|
||||
docker cp "$here/notification-sink.py" "$sink:/sink.py" >/dev/null
|
||||
docker start "$sink" >/dev/null
|
||||
sleep 1
|
||||
sink_ip="$(ip rr-nsink)"
|
||||
echo ">> sink at $sink_ip:9000"
|
||||
|
||||
echo ">> registering abonnement + creating a zaak"
|
||||
docker rm -f rr-nverify >/dev/null 2>&1 || true
|
||||
drv="$(docker create --network "$net" --name rr-nverify \
|
||||
-e "OZ_BASE=http://$oz_ip:8000" -e "NRC_BASE=http://$nrc_ip:8000" \
|
||||
-e "SINK_CALLBACK=http://$sink_ip:9000/" -e "SINK_AUTH=$SINK_AUTH" \
|
||||
python:3-slim python /driver.py)"
|
||||
docker cp "$here/verify-notification-driver.py" "$drv:/driver.py" >/dev/null
|
||||
docker start -a "$drv"
|
||||
zaak_url="$(docker logs rr-nverify 2>/dev/null | sed -n 's/^ZAAK_CREATED //p' | head -1)"
|
||||
docker rm -f rr-nverify >/dev/null
|
||||
[ -n "$zaak_url" ] || { echo "ERROR: driver did not create a zaak" >&2; exit 1; }
|
||||
zaak_uuid="${zaak_url##*/}"
|
||||
echo ">> zaak created: $zaak_url"
|
||||
|
||||
echo ">> waiting for the notification to reach the sink"
|
||||
for _ in $(seq 1 30); do
|
||||
if docker logs rr-nsink 2>&1 | grep -q "$zaak_uuid"; then
|
||||
echo "OK — NRC delivered the zaken notification for zaak $zaak_uuid to the sink"
|
||||
docker logs rr-nsink 2>&1 | grep "$zaak_uuid" | tail -1 | cut -c1-300
|
||||
exit 0
|
||||
fi
|
||||
sleep 2
|
||||
done
|
||||
echo "FAIL — the sink never received a notification for zaak $zaak_uuid" >&2
|
||||
echo "--- sink log ---" >&2; docker logs rr-nsink 2>&1 | tail -8 >&2
|
||||
exit 1
|
||||
bash "$here/run-notification-check.sh"
|
||||
|
||||
Reference in New Issue
Block a user