fix(infra): let Objecten actually accept the register record (refs #149)
Replaying the gateway's calls against a live Objecten + Objecttypen pair turned up two blockers CI would only have found after the fact: - Objecten rejects an objecttype it has not been configured with, and it identifies one by uuid — assigned at seed time by a one-shot that runs after Objecten's static setup_configuration. Pin the uuid on both sides instead. - Objecten notifies on every write and notifications_api_common *raises* when that config is absent, so every POST 500'd after rolling the object back. Objecten → NRC has no broker, worker, kanaal or abonnement yet, so disable notifications rather than wire a client that drops every message; S-19b turns them on for real. With both in place the full exchange verifies end to end: lookup → version → search → create → update (still one object), and a record carrying a bsn is rejected by the schema. ADR-0028 records both.
This commit is contained in:
@@ -77,6 +77,38 @@ is not cached, so it is retried on the next approval.
|
||||
- Upgrade path: lift it into a singleton cache (as `CachedZaaktypeCatalog` does for ZGW)
|
||||
if approvals ever get hot enough for that GET to matter.
|
||||
|
||||
### The objecttype's UUID is pinned, not server-assigned
|
||||
|
||||
Objecten refuses to store an object whose objecttype it has not been configured with
|
||||
(`ObjectType with url=… is not configured`), and its configuration identifies an
|
||||
objecttype **by UUID** — supplied through a static `setup_configuration` file applied
|
||||
when the container starts, before the `registerrecord-init` one-shot has run.
|
||||
|
||||
Rather than thread a seed-time UUID from one container into another's config, the UUID is
|
||||
**pinned**: `infra/objecttypen-registerrecord/register.py` creates the objecttype with a
|
||||
fixed UUID (the Objecttypen API accepts a client-supplied one), and
|
||||
`infra/objecten/setup_configuration/data.yaml` declares that same UUID. Both sides are
|
||||
declared up front, both stay idempotent, and neither has to wait for the other.
|
||||
|
||||
The cost is a constant duplicated across two files that must be kept in step; each carries
|
||||
a comment pointing at the other.
|
||||
|
||||
### Objecten's notifications are off for this slice
|
||||
|
||||
Objecten publishes to a Notificaties API on every write, and `notifications_api_common`
|
||||
**raises** rather than skipping when that configuration is absent — so with no NRC wiring,
|
||||
every `POST /api/v2/objects` returns 500 after creating and rolling back the object.
|
||||
|
||||
Objecten → NRC is not wired: there is no broker, no Celery worker, no `objecten` kanaal and
|
||||
no abonnement for it. Configuring only the client side would make writes succeed while
|
||||
every message was dropped on the floor — a delivery path that looks wired and isn't. So
|
||||
`NOTIFICATIONS_DISABLED` is set for Objecten in both compose files instead.
|
||||
|
||||
- ponytail ceiling: Objecten emits no notifications, so nothing downstream can react to a
|
||||
register write yet.
|
||||
- Upgrade path: S-19b (#150) needs those notifications to source the projection from
|
||||
Objecten, and turns them on together with the broker, worker, kanaal and abonnement.
|
||||
|
||||
## Consequences
|
||||
|
||||
**Positive**
|
||||
@@ -95,6 +127,8 @@ is not cached, so it is retried on the next approval.
|
||||
Nothing repairs that automatically yet.
|
||||
- One more upstream module on the approval path, and one more dev credential
|
||||
(`Acl__Objecten__Token`) in compose.
|
||||
- Two new hand-kept constants: the pinned objecttype UUID (two files) and the objecttype
|
||||
name (compose + `register.py`).
|
||||
- Until S-19b lands, the public register is still read from the NRC-derived projection, so
|
||||
the register record is written but not yet read — the two must agree.
|
||||
|
||||
@@ -110,3 +144,8 @@ and no service reaches Objecten's database.
|
||||
asserts, via `infra/register-record-check.py`, that Objecten holds exactly one
|
||||
`RegisterRecord` for that registration, with status `INGESCHREVEN` and no field outside
|
||||
the public-safe schema.
|
||||
|
||||
Every HTTP exchange the gateway performs was additionally replayed by hand against a live
|
||||
Objecten + Objecttypen pair while writing this slice — objecttype lookup by name, version
|
||||
status, `data_attrs` search, create, update, and a rejected write carrying a `bsn`. Both
|
||||
findings above came out of that replay rather than out of CI.
|
||||
|
||||
@@ -691,6 +691,12 @@ services:
|
||||
CACHE_AXES: objecten-redis:6379/0
|
||||
DISABLE_2FA: "true"
|
||||
OTEL_SDK_DISABLED: "true"
|
||||
# S-19a: Objecten refuses every write while its Notificaties config is absent
|
||||
# (notifications_api_common raises rather than skipping, so POST /objects 500s). Objecten →
|
||||
# NRC is not wired yet — there is no broker, worker, kanaal or abonnement for it — so turn
|
||||
# notifications off rather than fake a delivery path that silently drops every message.
|
||||
# S-19b (#150) sources the projection from Objecten and turns this back on for real.
|
||||
NOTIFICATIONS_DISABLED: "true"
|
||||
RUN_SETUP_CONFIG: "true"
|
||||
command: /setup_configuration.sh
|
||||
volumes:
|
||||
|
||||
@@ -717,6 +717,12 @@ services:
|
||||
CACHE_AXES: objecten-redis:6379/0
|
||||
DISABLE_2FA: "true"
|
||||
OTEL_SDK_DISABLED: "true"
|
||||
# S-19a: Objecten refuses every write while its Notificaties config is absent
|
||||
# (notifications_api_common raises rather than skipping, so POST /objects 500s). Objecten →
|
||||
# NRC is not wired yet — there is no broker, worker, kanaal or abonnement for it — so turn
|
||||
# notifications off rather than fake a delivery path that silently drops every message.
|
||||
# S-19b (#150) sources the projection from Objecten and turns this back on for real.
|
||||
NOTIFICATIONS_DISABLED: "true"
|
||||
RUN_SETUP_CONFIG: "true"
|
||||
command: /setup_configuration.sh
|
||||
# data.yaml is streamed into this external volume by infra/seed-config.sh before start.
|
||||
|
||||
@@ -19,7 +19,18 @@ zgw_consumers:
|
||||
header_key: Authorization
|
||||
header_value: Token 0123456789abcdef0123456789abcdef01234567
|
||||
|
||||
# (2) Static API token peers use to write/read objects.
|
||||
# (2) Permit the RegisterRecord objecttype (S-19a). Objecten refuses to store an object whose
|
||||
# objecttype it has not been configured with ("ObjectType with url=… is not configured"), and it
|
||||
# identifies one by uuid — which is why infra/objecttypen-registerrecord/register.py pins that uuid
|
||||
# instead of letting Objecttypen assign one. Keep the two in step.
|
||||
objecttypes_config_enable: true
|
||||
objecttypes:
|
||||
items:
|
||||
- uuid: 1f4b4e26-8b1f-4e2f-9d6c-6a1b7a2f0e01
|
||||
name: RegisterRecord
|
||||
service_identifier: objecttypen
|
||||
|
||||
# (3) Static API token peers use to write/read objects.
|
||||
tokenauth_config_enable: true
|
||||
tokenauth:
|
||||
items:
|
||||
|
||||
@@ -17,6 +17,11 @@ BASE = os.environ.get("OBJECTTYPEN", "http://objecttypen:8000").rstrip("/")
|
||||
TOKEN = os.environ["OBJECTTYPEN_TOKEN"]
|
||||
SCHEMA_PATH = os.environ.get("SCHEMA", "/config/registerrecord.schema.json")
|
||||
NAME = "RegisterRecord"
|
||||
# Pinned rather than server-assigned (S-19a): the Objecten API will only accept objects whose
|
||||
# objecttype it has been configured with *by uuid*, and its own setup_configuration is a static
|
||||
# file applied before this one-shot runs. A fixed uuid lets both sides be declared up front instead
|
||||
# of threading a seed-time value between two containers. See infra/objecten/setup_configuration.
|
||||
UUID = "1f4b4e26-8b1f-4e2f-9d6c-6a1b7a2f0e01"
|
||||
|
||||
|
||||
def api(method, path, body=None):
|
||||
@@ -53,6 +58,7 @@ def main():
|
||||
return 0
|
||||
|
||||
ot = existing or api("POST", "/api/v2/objecttypes", {
|
||||
"uuid": UUID,
|
||||
"name": NAME,
|
||||
"namePlural": "RegisterRecords",
|
||||
"description": schema.get("description", ""),
|
||||
|
||||
Reference in New Issue
Block a user