CI / changes (push) Successful in 8s
CI / lint (push) Successful in 12s
CI / frontend (push) Successful in 14s
CI / storybook-a11y (push) Successful in 17s
CI / backend (push) Successful in 1m51s
CI / semgrep (push) Successful in 1m13s
CI / e2e (push) Successful in 2m56s
CI / api-client-drift (push) Successful in 1m41s
docker-compose.openzaak.prod.yml layers real SECRET_KEY/DB password/site
domain/allowed-hosts (all required, fail-fast via ${VAR:?...}) on top of the
WP-54 dev harness, switches Postgres off trust auth, and sets IS_HTTPS for a
front-facing reverse-proxy TLS setup. The ZGW client secret lives inside a
file setup_configuration reads rather than a compose env var, so it's
templated (data.prod.yaml.template, no secret) and rendered host-side via
render-prod-secrets.sh into a gitignored data.prod.yaml, mounted over the
container's dev data.yaml. ZgwOptions.cs already binds from IConfiguration,
so the BFF side needed no code change.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
117 lines
6.7 KiB
Markdown
117 lines
6.7 KiB
Markdown
# OpenZaak integration harness (WP-54)
|
|
|
|
A real OpenZaak, for developing/testing the ZGW seam (`backend/src/BigRegister.Api/Zgw/`)
|
|
against something that isn't a fixture or a stub `HttpMessageHandler`. Deliberately **not**
|
|
part of the root `docker-compose.yml` and **not** wired into `npm run ci` / CI — see
|
|
[docs/reference/openzaak-integration.md](../../docs/reference/openzaak-integration.md) for the
|
|
full picture; this is just "how to run it".
|
|
|
|
## Bring it up
|
|
|
|
```bash
|
|
cd backend/openzaak
|
|
docker compose -f docker-compose.openzaak.yml up -d # postgres, redis, migrate+configure, OpenZaak
|
|
./bootstrap-catalogus.sh # seeds a catalogus/zaaktype/zaak to read back
|
|
```
|
|
|
|
`bootstrap-catalogus.sh` waits for OpenZaak to answer, then over plain REST + a hand-rolled
|
|
HS256 JWT (same shape as `ZgwTokenProvider.cs`, matching the `bigregister-test` client
|
|
`setup_configuration/data.yaml` creates): a catalogus, a published zaaktype ("Herregistratie
|
|
arts", with the statustypen/resultaattype/roltype OpenZaak requires before a zaaktype can be
|
|
published), and one zaak (`BIG-2026-000123`) with an initiator rol for the seeded BSN
|
|
(`111222333` — the same fixture BSN `OpenZaakZaakSourceTests.cs` uses). It writes what it
|
|
seeded to `seeded.env` (gitignored) and prints a summary.
|
|
|
|
**Not idempotent** — re-running against the same (already-seeded) instance fails on OpenZaak's
|
|
`domein`+`rsin` uniqueness constraint for the catalogus. Reset with:
|
|
|
|
```bash
|
|
docker compose -f docker-compose.openzaak.yml down -v && docker compose -f docker-compose.openzaak.yml up -d
|
|
```
|
|
|
|
## Run the integration test against it
|
|
|
|
```bash
|
|
cd backend
|
|
dotnet test --filter Category=Integration
|
|
```
|
|
|
|
`OpenZaakIntegrationTests.cs` points a `WebApplicationFactory<Program>` at
|
|
`Zgw:Enabled=true` + `http://localhost:8000` with the harness's credentials, hits
|
|
`GET /api/v1/admin/cases`, and asserts the seeded zaak comes back — through the real HTTP +
|
|
JWT + Catalogi-label-resolution path, not a mock. This test is tagged `Category=Integration`
|
|
and is **excluded** from the default `dotnet test` run and from CI (`ci.yml`,
|
|
`scripts/ci-local.sh` both filter `Category!=Integration`) — it only passes with this harness
|
|
up, so it never runs where the harness doesn't exist.
|
|
|
|
## Tear down
|
|
|
|
```bash
|
|
docker compose -f docker-compose.openzaak.yml down -v
|
|
```
|
|
|
|
## Production (WP-55)
|
|
|
|
This dev harness stays dev-only: hardcoded `SECRET_KEY`, `POSTGRES_HOST_AUTH_METHOD=trust`,
|
|
`IS_HTTPS: 'no'`, a client secret checked into `setup_configuration/data.yaml`. A real
|
|
deployment layers `docker-compose.openzaak.prod.yml` on top instead of replacing anything:
|
|
|
|
```bash
|
|
export OPENZAAK_SECRET_KEY=... # Django SECRET_KEY — generate, don't reuse the dev value
|
|
export OPENZAAK_DB_PASSWORD=... # postgres password (switches auth off `trust`)
|
|
export OPENZAAK_SITE_DOMAIN=... # e.g. open-zaak.example.org — no scheme/port
|
|
export OPENZAAK_ALLOWED_HOSTS=... # Django ALLOWED_HOSTS, usually the same domain
|
|
export OPENZAAK_CLIENT_ID=... # the BFF's OpenZaak client id (ZgwOptions:ClientId)
|
|
export OPENZAAK_CLIENT_SECRET=... # the BFF's JWT signing secret (ZgwOptions:Secret)
|
|
export OPENZAAK_APPLICATIE_UUID=$(uuidgen)
|
|
|
|
./render-prod-secrets.sh # writes the gitignored setup_configuration/data.prod.yaml
|
|
docker compose -f docker-compose.openzaak.yml -f docker-compose.openzaak.prod.yml up -d
|
|
```
|
|
|
|
Every one of those env vars is `${VAR:?...}`-checked — compose (and `render-prod-secrets.sh`
|
|
for the client secret) refuses to start rather than silently falling back to a dev-looking
|
|
default. There is no env var that "means insecure default"; if it's unset, it's a hard error.
|
|
|
|
**TLS**: OpenZaak itself does no certificate handling. Put a reverse proxy/ingress (the same
|
|
one fronting the BFF) in front of `web`'s `:8000`, terminate TLS there, and forward to
|
|
`http://web:8000` over the compose network. `IS_HTTPS: 'yes'` in the prod override only tells
|
|
Django it's being served over HTTPS (secure cookies, `SECURE_*` redirects) — it does not open
|
|
a TLS listener itself.
|
|
|
|
The BFF side needs no code change: `ZgwOptions` already binds `ClientId`/`Secret`/the base
|
|
URLs from `IConfiguration`, so pointing it at a production OpenZaak is a config change
|
|
(`Zgw:ClientId`/`Zgw:Secret`/`Zgw:ZrcBaseUrl` etc. via env vars or a secrets manager), not an
|
|
app change.
|
|
|
|
## What's in here / what isn't
|
|
|
|
- `docker-compose.openzaak.yml` — postgres (postgis), redis, a one-shot `web-init` (runs
|
|
Django migrations then `setup_configuration` against `setup_configuration/data.yaml`), and
|
|
`web` (the OpenZaak API on `:8000`). Pinned to `openzaak/open-zaak:1.29.1`. No
|
|
celery/celery-beat/celery-flower/nginx — trimmed for a lean, fast-booting harness; add them
|
|
back only if a later WP needs a real async notification delivery round-trip here (WP-52's
|
|
webhook is already covered by fixture tests against no live instance).
|
|
`NOTIFICATIONS_DISABLED=true` is required, not optional: without it, OpenZaak 500s (and
|
|
**rolls back the whole create**) on any notified resource — see the compose file's comment.
|
|
- `setup_configuration/data.yaml` — the declarative, scripted alternative to clicking through
|
|
the Django admin (upstream's own documented `setup_configuration` CLI mechanism): creates the
|
|
one `bigregister-test` client (`heeft_alle_autorisaties: true` — this instance never exists
|
|
for anything but this harness, so there's no least-privilege boundary worth modeling).
|
|
- `bootstrap-catalogus.sh` — the business content (catalogus/zaaktype/zaak/…) `setup_configuration`
|
|
has no YAML for; every field value here was checked against OpenZaak's own OpenAPI spec and a
|
|
live run of this exact script, not guessed (two OpenZaak quirks it works around: a zaaktype
|
|
needs ≥1 resultaattype and 2 statustypen before it can be published, and its
|
|
`selectielijstklasse` and the zaaktype's `selectielijstProcestype` must reference the same
|
|
`procesType` on the public VNG selectielijst API).
|
|
- **Not here**: Documenten (DRC) / Notificaties (NRC) content — add if a later WP needs to prove
|
|
those round-trips against a live instance too (WP-51/52 are fixture-tested today).
|
|
- `docker-compose.openzaak.prod.yml` (WP-55) — production overrides layered on top of
|
|
`docker-compose.openzaak.yml`: real `SECRET_KEY`/DB password/site domain/allowed-hosts from
|
|
required env vars (fails fast if unset), password DB auth instead of `trust`, `IS_HTTPS: 'yes'`.
|
|
Adds no image/service of its own — see "Production" above for the full flow.
|
|
- `setup_configuration/data.prod.yaml.template` (WP-55) — the prod counterpart of `data.yaml`
|
|
with no secret in it (`${OPENZAAK_CLIENT_SECRET}` etc. as placeholders); `render-prod-secrets.sh`
|
|
fills it in to the gitignored `data.prod.yaml`, which the prod compose override mounts over
|
|
the container's `data.yaml`.
|