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)
|
- Upgrade path: lift it into a singleton cache (as `CachedZaaktypeCatalog` does for ZGW)
|
||||||
if approvals ever get hot enough for that GET to matter.
|
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
|
## Consequences
|
||||||
|
|
||||||
**Positive**
|
**Positive**
|
||||||
@@ -95,6 +127,8 @@ is not cached, so it is retried on the next approval.
|
|||||||
Nothing repairs that automatically yet.
|
Nothing repairs that automatically yet.
|
||||||
- One more upstream module on the approval path, and one more dev credential
|
- One more upstream module on the approval path, and one more dev credential
|
||||||
(`Acl__Objecten__Token`) in compose.
|
(`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
|
- 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.
|
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
|
asserts, via `infra/register-record-check.py`, that Objecten holds exactly one
|
||||||
`RegisterRecord` for that registration, with status `INGESCHREVEN` and no field outside
|
`RegisterRecord` for that registration, with status `INGESCHREVEN` and no field outside
|
||||||
the public-safe schema.
|
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
|
CACHE_AXES: objecten-redis:6379/0
|
||||||
DISABLE_2FA: "true"
|
DISABLE_2FA: "true"
|
||||||
OTEL_SDK_DISABLED: "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"
|
RUN_SETUP_CONFIG: "true"
|
||||||
command: /setup_configuration.sh
|
command: /setup_configuration.sh
|
||||||
volumes:
|
volumes:
|
||||||
|
|||||||
@@ -717,6 +717,12 @@ services:
|
|||||||
CACHE_AXES: objecten-redis:6379/0
|
CACHE_AXES: objecten-redis:6379/0
|
||||||
DISABLE_2FA: "true"
|
DISABLE_2FA: "true"
|
||||||
OTEL_SDK_DISABLED: "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"
|
RUN_SETUP_CONFIG: "true"
|
||||||
command: /setup_configuration.sh
|
command: /setup_configuration.sh
|
||||||
# data.yaml is streamed into this external volume by infra/seed-config.sh before start.
|
# 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_key: Authorization
|
||||||
header_value: Token 0123456789abcdef0123456789abcdef01234567
|
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_config_enable: true
|
||||||
tokenauth:
|
tokenauth:
|
||||||
items:
|
items:
|
||||||
|
|||||||
@@ -17,6 +17,11 @@ BASE = os.environ.get("OBJECTTYPEN", "http://objecttypen:8000").rstrip("/")
|
|||||||
TOKEN = os.environ["OBJECTTYPEN_TOKEN"]
|
TOKEN = os.environ["OBJECTTYPEN_TOKEN"]
|
||||||
SCHEMA_PATH = os.environ.get("SCHEMA", "/config/registerrecord.schema.json")
|
SCHEMA_PATH = os.environ.get("SCHEMA", "/config/registerrecord.schema.json")
|
||||||
NAME = "RegisterRecord"
|
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):
|
def api(method, path, body=None):
|
||||||
@@ -53,6 +58,7 @@ def main():
|
|||||||
return 0
|
return 0
|
||||||
|
|
||||||
ot = existing or api("POST", "/api/v2/objecttypes", {
|
ot = existing or api("POST", "/api/v2/objecttypes", {
|
||||||
|
"uuid": UUID,
|
||||||
"name": NAME,
|
"name": NAME,
|
||||||
"namePlural": "RegisterRecords",
|
"namePlural": "RegisterRecords",
|
||||||
"description": schema.get("description", ""),
|
"description": schema.get("description", ""),
|
||||||
|
|||||||
Reference in New Issue
Block a user