--- title: 'DD-0043: The Retained Themelio as the themelio-compat Service' --- # DD-0043 — The retained Themelio as the `themelio-compat` service **Related ADR:** [ADR-0043](../decisions/0043-themelio-compat-service.md). **Status:** Draft for review. Qualified on the authorised `dev-ikons` dev box; other dev boxes remain pending. Staging and production do not run it. **Date:** 2026-10-14. ## Scope and responsibilities This is infrastructure configuration, stage 4 of [decision 0040](../decisions/0040-platform-layout.md), for the legacy source relocated under [decision 0042](../decisions/0042-legacy-source-relocation.md). There is no new business context, aggregate, command API, event or subscription. | Owner | Responsibility | |---|---| | Ansible bootstrap | The `themelio-compat` namespace, its Pod Security labels and the controller's Role in it | | Argo CD | The web, both actors, PostgreSQL, Valkey, generated Secrets, the database Jobs and the network policies; Waldur's Identity Bridge setting | | `make deploy` | The images and their digests, the AAI client Secret and the GitLab and Waldur tokens | ## Application and manifests Every dev box installs the `themelio-compat` Application (`gitops/apps/base/themelio-compat.yaml`) on wave 4, after GitLab and Waldur. `apps/overlays/devbox` sets its path, and `apps/base` patches Waldur's Application with the Identity Bridge setting. When the new Themelio replaces it, it becomes an optional component again ([ADR-0045](../decisions/0045-development-loop.md)). An earlier saved `themelio-compat` profile is still accepted and has no effect. The Application installs `gitops/manifests/themelio-compat/overlays/devbox`: - `base/` holds plain manifests, one file per workload or concern, as `legacy/gitops/manifests/themelio` does. Its `configMapGenerator` names the configuration with a content hash, so a change rolls the pods that read it at start. Superseded ConfigMaps carry `IgnoreExtraneous`, so they stay (the root does not prune) without marking the service OutOfSync. - `overlays/devbox/` merges the dev box's public origins into that configuration. `check_platform_gitops.py` builds the service as Argo does with the root's images. Every container image must be a digest, and the `docker.io/pharos/themelio-compat-*` ones must be the digests of the in-cluster builds. Without them the build fails the check. `model.application_errors` accepts only `kustomize.images` on this Application. ## Images The `web`, `gitlab-root-actor` and `k8s-root-actor` targets are entries of the image catalogue, built in the cluster from the delivered commit ([DD-0045](0045-development-loop.md)). The Dockerfile copies all of `compat/themelio`, so a change anywhere in it rebuilds all three. The root passes their digests as the Application's `kustomize.images`. The web pins Next.js 15.5.7. Its loopback rewrite matches `127.x.x.x` anywhere in a URL, so `themelio-compat.pharos.127.0.0.1.sslip.io` became `...pharos.localhost.sslip.io` and the OIDC redirect URI no longer matched. Next.js 16 anchors the rule to the host. No 15.5 release does. `compat/themelio/next-loopback.cjs` applies the anchored rule to the 27 affected files before the build and fails on any other version or count, so an upgrade is reviewed. ## Data and credentials PostgreSQL 17 and Valkey 8.1 run in the namespace on Ceph block volumes, pinned by digest. A Sync hook creates the generated Secrets once: the PostgreSQL administrator, migrator and runtime passwords, the Valkey password, the web's session secret and the actors' internal token. The provision Job alone reads the administrator password and creates the two roles. The migration Job runs DDL as the migrator, and the Kubernetes root actor runs as the runtime role. The provider tokens are the exception in [ADR-0043](../decisions/0043-themelio-compat-service.md). While Argo installs the services, `make deploy` waits for GitLab and Waldur to be Synced and Healthy. It then: - creates root's `themelio-compat-root-actor` token (`api`, `sudo`), revoking earlier ones, for the GitLab root actor only; - creates the password-less staff user `themelio-compat` and its single token, for the web only. The values reach GitLab, Waldur and Kubernetes only on stdin. Each token expires after 30 days. A deploy rotates it when fewer than seven days remain and restarts only the workload that reads it. ## Sign-in, Waldur and routes Themelio signs in through the shared AAI's `pharos-control-plane` client, which gains its callback. `aai-client.yaml` makes `make deploy` render the client and the AAI CA into the `themelio-oidc` Secret. Every Themelio process trusts that CA, which also signs the edge. The web requests only the scopes the AAI defines: `openid`, `voperson_id`, `email`, `profile`, `voperson_external_affiliation`, `schac_home_organization` and `entitlements`. On sign-in, the web creates or updates the user in Waldur through the Identity Bridge. Waldur's wrapper chart gains `pharos.settings`, Constance settings declared in the synced `pharos-settings` ConfigMap. Its PostSync bootstrap applies them with `waldur override_constance_settings`. Argo runs the hook only when a synced resource changes, so the settings cannot live in the hook alone. The command skips a setting it cannot save and still succeeds, so the hook fails on its report. The apps set `FEDERATED_IDENTITY_SYNC_ENABLED`, and Waldur keeps it set if the service is later removed. The catalogue route `themelio-compat.pharos` reaches the web. Network policies deny ingress except from the namespace and the gateway's paired policy, and apply before the data servers start. ## Qualification and remaining boundaries On `dev-ikons`: - **Sign-in:** alice and bob sign in through the AAI in Chromium, which trusts only the AAI CA, and land on the dashboard (`dx/common/scripts/service-login.sh themelio-compat`). - **Waldur:** the bootstrap reports `FEDERATED_IDENTITY_SYNC_ENABLED has been set to True`, and the web syncs alice and bob into Waldur on sign-in. The check requires the setting on every dev box. - **GitLab:** alice and bob are GitLab users with the `openid_connect` identity. Not exercised: a first sync of a user Waldur does not yet know, action execution (spaces, inference services, Slurm jobs), egress isolation, fresh-VM and reboot qualification, and other dev boxes.