From 77452492ec0ca914948bcb00d9ee5a3942f807cb Mon Sep 17 00:00:00 2001 From: tegwick Date: Tue, 18 Aug 2026 12:21:49 +0200 Subject: [PATCH] docs: treat live net-kingdom user-engine manifests as the wrap source user-engine already runs from net-kingdom/sso-mfa/k8s/user-engine. The rapp absorbs those manifests (manifest-managed), keeps or cutovers the dedicated CNPG cluster, and becomes the only apply home. --- docs/RailianceAppDeploymentGuide.md | 148 +++++++++++------- ...MGR-WP-0006-railiance-app-wrapper-setup.md | 13 +- 2 files changed, 103 insertions(+), 58 deletions(-) diff --git a/docs/RailianceAppDeploymentGuide.md b/docs/RailianceAppDeploymentGuide.md index 57c8b7b..0a64a8c 100644 --- a/docs/RailianceAppDeploymentGuide.md +++ b/docs/RailianceAppDeploymentGuide.md @@ -456,7 +456,8 @@ to `rapp-` and keep `railiance/app.toml` inside the rapp. ### 9.1 Database -Do not run a sidecar Postgres. Declare a consumer against `rapp-postgres`: +Do not run a sidecar Postgres. The default for a new app is a consumer +against `rapp-postgres`: - boundary unit: `database-per-consumer` - credential lane: `railiance-platform-credential-broker` @@ -472,6 +473,11 @@ If the app consumes a single `DATABASE_URL`, URL-encode the password. Prefer discrete `POSTGRES_*` env vars when the framework allows it (`railiance-apps/docs/django-on-railiance.md`). +A **dedicated CNPG Cluster** is allowed only when placement policy +already says so (live `user-engine-pg` is this case). Then the Cluster +manifests belong in the rapp, not in `net-kingdom` or the app repo. Do +not be both a `rapp-postgres` consumer and a dedicated Cluster. + ### 9.2 Secrets The rapp never stores values. Standing secrets go through a CCR and @@ -524,7 +530,7 @@ a grantable public surface. ### 10.1 Current facts `user-engine` is a headless user-domain / identity-domain service with a -production WSGI portal. It already has: +production WSGI portal. The **app repo** already has: - `Containerfile` — Python 3.12 slim, non-root uid `10001`, port `8080` - `python -m user_engine.runtime` @@ -532,14 +538,40 @@ production WSGI portal. It already has: - Postgres store + in-tree migrations - fail-closed production adapters: OIDC, flex-auth, outbox, provisioning, optional tenant-management and registration verification -- explicit non-ownership of IdP, authorization PDP, and secret custody +- explicit non-ownership of IdP, authorization PDP, secret custody, **and + deployment** (`docs/release.md`) -`rapp-user-engine` is an empty git repository (2026-08-11). ADR-0007 -already lists it as undeclared. +`rapp-user-engine` is an empty Forgejo clone +(`forgejo-remote:coulomb/rapp-user-engine.git`). No README, no +declaration. ADR-0007 already lists it as undeclared. -Sister stubs `rapp-secrets-engine` and `rapp-tenant-engine` should follow -the same guide after user-engine proves the path. Do not batch-scaffold -all three before the first declaration validates. +**Live packaging is not in the rapp.** It lives in +`net-kingdom/sso-mfa/k8s/user-engine/`: + +| File | Role | +| --- | --- | +| `runtime.yaml` | Namespace, dedicated CNPG `user-engine-pg`, Deployment, Service, SA, NetworkPolicies | +| `ingress.yaml` | Traefik Ingress `users.92-205-62-239.nip.io` (README still says no public Ingress until KeyCape PKCE is configured — treat exposure as unresolved) | +| `openbao-runtime.yaml` | ExternalSecrets from `platform/workloads/user-engine/runtime` | +| `backup.yaml`, `restore-drill.yaml` | Logical dump / restore | +| `verify-operability.sh` | Live checks | + +Image already published: +`forgejo.coulomb.social/coulomb/user-engine@sha256:e3b5f65bafc1c0260dfdf2567a52766e67506ceb878a51759a2e9a307c4b5eb8`. +flex-auth for this consumer is pinned **inside** `flex-auth` +(`values/user-engine.yaml`, `examples/user-engine/`), not in a rapp. +Closest sibling analogue: `tenant-engine/deploy/` (digest-pinned +manifests, but that app *is* a `rapp-postgres` consumer). + +The wrapper job is therefore **absorb and declare**, not invent a second +production target. Same rule as +`qonto-assistant/docs/knative-runtime-and-rapp-handoff.md`: once the +rapp exists, `net-kingdom` keeps IAM/provisioner contracts and stops +being the apply home. + +Sister stubs `rapp-secrets-engine` and `rapp-tenant-engine` follow after +this path validates. `rapp-secrets-engine` is likely a grouping mistake +against `rapp-openbao` / S3, not a fourth identity member. ### 10.2 Recommended decisions @@ -548,12 +580,12 @@ all three before the first declaration validates. | Create a rapp? | yes | stable identity, clear app/wrapper split, own rollout fate | | `ownership_repo` | `user-engine` | application accountability, same pattern as `policy-nexus` / `qonto-assistant` | | `workload_identity.name` | `user-engine` | schema rule | -| `package_type` | `helm-managed-platform-service` | only Helm-shaped enum available today | +| `package_type` | `manifest-managed-platform-service` | live assets are raw YAML/CNPG, not a Helm chart. Do not invent Helm just to match policy-nexus. | | `primary_rail` | `rail-kubernetes` | long-running portal + durable store; no Knative need | | `bound_reefs` | `[]` at `declared`; `[reef-railiance]` when placed | empty is legal and means "not yet placed" | | `data_classification` | `confidential` | identity and account data | | `criticality` | `high` | shared identity-domain service; not the secrets/postgres critical path | -| `exposure` | omit (private) | operator tunnel later if needed; public grant only with a hostname and residual-risk owner | +| `exposure` | omit (private) until the KeyCape PKCE edge is decided | an Ingress object already exists; that is **not** a grant (ADR-0008). Decide hostname + residual-risk owner before `public`. | | Granularity | single-repo rapp **for the pilot** | one deployable; do not group with tenant-engine or secrets-engine unless they share rollback fate. `rapp-first-wave-candidates.md` still flags a future grouped `rapp-netkingdom-identity` (user-engine + tenant-engine + key-cape + flex-auth). That grouping is only legal if those members cannot roll back independently — they almost certainly can. Treat the grouped name as a later composition question, not as a reason to leave `rapp-user-engine` undeclared. | ### 10.3 Draft declaration (index, not authority) @@ -572,9 +604,7 @@ contract_version: 1.0.0 readiness_state: draft workload_identity: name: user-engine - package_type: helm-managed-platform-service - chart: rapp-user-engine/user-engine - chart_version: 0.1.0 + package_type: manifest-managed-platform-service app_version: 0.1.0 data_classification: confidential criticality: high @@ -586,28 +616,28 @@ runtime_dependencies: - kubernetes-api - helm-apply-path - forgejo-oci-registry - - openbao-database-secrets-engine + - pvc-storage - keycape-oidc - flex-auth + - openbao + - audit-core + - tenant-engine +secret_references: + - platform/workloads/user-engine/runtime composition: purpose: Package and operate the user-engine identity-domain service on Railiance. member_repos: - repo: rapp-user-engine - role: Helm package, smoke, and rollback for the user-engine runtime + role: Kubernetes manifests, smoke, and rollback for the user-engine runtime deployables: - user-engine - - repo: user-engine - role: application source, image, and schema migrations - deployables: - - user-engine-migrate upstream_components: - name: user-engine - source: forgejo.coulomb.social//user-engine - version: sha256: + source: forgejo.coulomb.social/coulomb/user-engine + version: sha256:e3b5f65bafc1c0260dfdf2567a52766e67506ceb878a51759a2e9a307c4b5eb8 rollout_contract: - default_mode: helm-upgrade-install + default_mode: kubectl-server-side-apply commands: - - make render - make server-dry-run - make deploy production_gate: reef-production-approved @@ -617,15 +647,15 @@ smoke_contract: - readyz-ok-when-store-ready - metrics-requires-proxy-marker - local-issuer-rejected-in-production - - postgres-consumer-database-present + - live-image-digest-match commands: - make verify-live rollback_contract: order: - - previous-helm-revision + - previous-immutable-image-digest - apply-reviewed-git-revision commands: - - make rollback REVISION= + - make rollback DIGEST= source_documents: - repo: user-engine path: INTENT.md @@ -633,22 +663,25 @@ source_documents: path: docs/configuration.md - repo: user-engine path: docs/operability.md - - repo: user-engine - path: docs/postgres-durable-store-consumer-requirements.md + - repo: net-kingdom + path: sso-mfa/k8s/user-engine/README.md - repo: railiance-master path: schemas/rapp.schema.json - repo: repo-manager path: docs/RailianceAppDeploymentGuide.md ``` -Cardinality note: `user-engine` the *Deployment* belongs to this rapp. -`user-engine-migrate` is a Job owned by the same rapp. Do not also list -the Deployment under another rapp. +Cardinality note: the live deployable name is `user-engine` (the +Deployment). Migrations run in-process before serve, so do **not** +invent a second `user-engine-migrate` deployable unless a separate Job +is added. `user-engine-pg` is a Cluster owned by this package only if +the dedicated-cluster decision stands; if it is inventoried as its own +deployable it still belongs to **this** rapp. -If the migrate Job is considered the same deployable as the app, collapse -to a single `user-engine` deployable and treat migration as a rollout -step, not a second live unit. Prefer the single-deployable form unless -the Job must be inventoried separately for the coverage check. +`ownership_repo: user-engine` already names the source repo. Do not also +claim the Deployment from `net-kingdom`. A single-member composition +matches every live rapp; add `user-engine` as a second member only if it +contributes a *different* deployable. ### 10.4 Runtime inputs the chart must accept @@ -681,26 +714,32 @@ Logical secret names the app already documents: `database.url`, in `railiance/app.toml`; do not invent a second naming scheme in the chart. -### 10.5 Postgres consumer (to be added in `rapp-postgres`) +### 10.5 Database decision (do not do both) -Sketch only — the owning package is `rapp-postgres`: +Live user-engine uses a **dedicated** CNPG Cluster `user-engine-pg` +(postgresql 17.5, db `user_engine`), not a `rapp-postgres` consumer. +tenant-engine and audit-core *are* platform consumers. -```yaml -apiVersion: rapp-postgres.railiance.io/v1alpha1 -kind: PostgresConsumer -metadata: - name: user-engine -spec: - database: user_engine - schema: user_engine - costAttributionKey: platform:user-engine - clientNamespaces: [user-engine] - roles: - owner: user_engine_owner - migration: user_engine_migrate - runtime: user_engine_app - tenantKeyingRequired: true -``` +Two legal next states: + +1. **Keep dedicated.** Move `user-engine-pg` manifests into the rapp. + Declare `pvc-storage` (and later `s3-backup-target` if backup is + attached). Do not add a postgres consumer. +2. **Become a consumer.** Add `rapp-postgres/consumers/user-engine.yaml` + (same shape as `audit-core.yaml`), delete the dedicated Cluster after + a reviewed cutover. Then drop `pvc-storage` from this rapp. + +Pick one in T04. The current live state is (1). + +### 10.6 Absorb the NetKingdom apply home + +T03 should copy +`net-kingdom/sso-mfa/k8s/user-engine/` into +`rapp-user-engine/manifests/` (or `helm/` only if a real chart is +justified), add Makefile `server-dry-run` / `deploy` / `verify-live` / +`rollback DIGEST=…`, and leave a pointer README in NetKingdom so there +is one apply path. Do not Helm-rewrite the live YAML in the same +change. ### 10.6 What stays in `user-engine` @@ -900,3 +939,6 @@ Worked example: - `user-engine/docs/postgres-durable-store-consumer-requirements.md` - `user-engine/Containerfile` - `user-engine/src/user_engine/runtime.py` +- `net-kingdom/sso-mfa/k8s/user-engine/` (current live apply home) +- `tenant-engine/deploy/` (closest sibling manifest package) +- `qonto-assistant/docs/knative-runtime-and-rapp-handoff.md` (one apply home) diff --git a/workplans/RMGR-WP-0006-railiance-app-wrapper-setup.md b/workplans/RMGR-WP-0006-railiance-app-wrapper-setup.md index e639dc8..8f31964 100644 --- a/workplans/RMGR-WP-0006-railiance-app-wrapper-setup.md +++ b/workplans/RMGR-WP-0006-railiance-app-wrapper-setup.md @@ -77,12 +77,15 @@ priority: high state_hub_task_id: "3ba6828e-7514-4f4d-a1d3-54134e039f55" ``` -Add the Helm chart, Makefile operator targets, `railiance/app.toml`, and -runtime-contract doc described in the guide, derived from `user-engine` -port, health paths, Containerfile user, and documented env/secret names. +Absorb `net-kingdom/sso-mfa/k8s/user-engine/` into +`rapp-user-engine/manifests/` (or a Helm chart only if a rewrite is +justified separately). Add Makefile `server-dry-run` / `deploy` / +`verify-live` / `rollback DIGEST=…` and a runtime-contract doc. Leave a +pointer in NetKingdom so there is one apply path. -`make render` and `make lint` must pass with dummy digests. No cluster -deploy in this task. +`make server-dry-run` must pass. No production apply in this task. +Package type is `manifest-managed-platform-service` unless the rewrite +to Helm is an explicit later decision. ## Draft platform handoffs