0ea562db526a1b64d5bdd4c0f51dd649851fceb2
6
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
0ea562db52 |
refactor(k8s): keep the big-demo theme as real files under infra/keycloak/themes (refs #177)
CI / lint (pull_request) Successful in 1m55s
CI / k8s (pull_request) Successful in 9s
CI / build (pull_request) Successful in 1m27s
CI / unit (pull_request) Successful in 1m51s
CI / frontend (pull_request) Successful in 3m24s
CI / mutation (pull_request) Successful in 6m40s
CI / verify-stack (pull_request) Failing after 1m1s
The theme was inline text in a Helm template. It now lives next to the realms and is seeded as rr-kc-theme by seed-configmaps.sh, like every other file input, so it can be edited as a normal Keycloak theme. demo.otpAutofill now only decides whether KC_SPI_THEME_DEFAULT is set (big.env skips values that render empty); off, Keycloak keeps its stock theme. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> |
||
|
|
6cd2268be9 |
fix(k8s): declare every theme type in big-demo so the account console loads (refs #177)
CI / lint (pull_request) Successful in 2m0s
CI / k8s (pull_request) Successful in 9s
CI / build (pull_request) Successful in 1m22s
CI / unit (pull_request) Successful in 1m34s
CI / verify-stack (pull_request) Canceled after 0s
CI / frontend (pull_request) Canceled after 3m8s
CI / mutation (pull_request) Canceled after 8m10s
KC_SPI_THEME_DEFAULT applies to all theme types and Keycloak does not fall back for one the theme lacks: the account console returned 500 (NPE on a null theme). The theme is now one ConfigMap mounted as a directory with login, account, admin and email types; the podspec gains `items` for that. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> |
||
|
|
1cc04de630 |
feat(k8s): optionally auto-fill the medewerker OTP step for the public demo (refs #177)
CI / k8s (pull_request) Successful in 13s
CI / build (pull_request) Successful in 5m36s
CI / unit (pull_request) Successful in 6m18s
CI / frontend (pull_request) Successful in 3m12s
CI / verify-stack (pull_request) Canceled after 0s
CI / mutation (pull_request) Canceled after 8m0s
CI / lint (pull_request) Canceled after 21m26s
A `big-demo` Keycloak login theme (keycloak.v2 + one script) is always mounted and set as default. With demo.otpAutofill (repo variable OTP_AUTOFILL=true) the script computes the code from the committed fixture secret and submits it, so the demo shows MFA enforced without an authenticator. Off by default: the script is empty and the login is plain keycloak.v2. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> |
||
|
|
804031eeb8 |
feat(k8s): publish the portals through the labs Caddy (refs #177) (#179)
CI / k8s (push) Successful in 14s
CI / build (push) Successful in 2m2s
CI / lint (push) Successful in 2m32s
CI / unit (push) Successful in 1m36s
CI / frontend (push) Successful in 3m3s
Deploy to Talos / deploy (push) Successful in 3m39s
CI / mutation (push) Successful in 5m31s
CI / verify-stack (push) Failing after 17m26s
## What & why Makes the portals reachable on real hostnames through the Caddy that already fronts `*.labs.respellion.tech`, instead of five SSH port-forwards: | URL | Service | |---|---| | `https://big-register.labs.respellion.tech` | openbaar | | `https://big-mijn.labs.respellion.tech` | self-service | | `https://big-behandel.labs.respellion.tech` | behandel | | `https://big-beheer.labs.respellion.tech` | beheer | | `https://big-auth.labs.respellion.tech` | Keycloak (`/admin` blocked) | Chain: browser → labs Caddy (TLS) → `openssh-server` container → reverse SSH tunnel → Fedora host → Talos NodePorts. The Caddy routes and the tunnel unit are already on `main` in the Infra repo (`infra/development/`). This repo's part: - **Chart:** a `keycloakUrl` value. When set it replaces `host` + Keycloak's NodePort as the pinned issuer (`KC_HOSTNAME`) and the portals' OIDC authority. Both now come from one helper, `big.keycloakUrl`, so they can't drift apart (ADR-0010). Empty = rendered output identical to today. - **Deploy workflow:** passes the `KEYCLOAK_URL` repo variable as `--set keycloakUrl=…`. - **Runbook:** new section "Publishing through the labs Caddy". Refs #177 ## Definition of Done - [x] Linked Gitea issue (above). - [ ] Failing test committed before the implementation. *(Infra/config change, no test added.)* - [x] Implementation makes the test pass; refactor commit if structure improved. - [x] Conventional Commits referencing the issue (`refs #NN`). - [ ] CI green — all Gitea Actions jobs (or `make ci` green while no runner exists). - [x] `docker compose up` from a fresh clone reaches green health checks within 3 minutes. *(Compose untouched.)* - [x] Docs updated if behaviour, contracts, or operations changed. - [ ] ADR added in `docs/architecture/` if a non-obvious decision was made. - [ ] Demo note in `docs/demo-script.md` if user-visible. ## Notes for reviewers - **This takes the option #177 rejects.** #177 proposes an in-cluster Caddy edge (branch `feat/177-public-tls-edge`). This PR uses the existing labs Caddy instead, because it already holds 80/443 and the wildcard certificate. So it only *refs* #177. If we go this way, #177's ADR should record the host-Caddy option instead. - `make k8s-lint` and `infra/check-docs-nav.py` pass. I rendered the chart with and without `keycloakUrl`: empty gives the same output as before; set, it gives `https://big-auth.labs.respellion.tech` for both the issuer and the authority. - Once `KEYCLOAK_URL` is set, the `localhost` port-forward workflow (runbook §5) no longer logs in, because the issuer is a single string. - The portals are public, with no Azure `authorize` in front of them the way `marketing` has one. The test users use `test123`. - Rollout after merge: install `big-portals-tunnel.service` on the Fedora host, run `docker compose up -d caddy` on the labs server, then set the `KEYCLOAK_URL` variable. 🤖 Generated with [Claude Code](https://claude.com/claude-code)Reviewed-on: #179 |
||
|
|
9d7e8e5b65 |
ci(k8s): gate the Helm chart in CI + a compose↔chart drift check (closes #168) (#171)
CI / k8s (push) Successful in 5s
CI / lint (push) Successful in 1m27s
CI / build (push) Successful in 1m22s
CI / unit (push) Successful in 1m12s
CI / frontend (push) Successful in 2m7s
CI / mutation (push) Successful in 3m9s
CI / verify-stack (push) Successful in 6m20s
## What & why The Helm chart landed in #167 with two gaps written into ADR-0033: `make k8s-lint` existed but no CI job ran it, and *"a second deployment description to keep in step with compose — nothing enforces that today; a drift check belongs in CI (follow-up)"*. Both are closed here. **`make k8s-drift`** (`infra/helm/check-drift.py`, stdlib only) compares what each stack actually deploys rather than diffing two files that differ by design: workload names and resolved container images, taken from `docker compose config --format json` and a rendered chart. The six differences that exist today are declared in `DEVIATIONS` with the reason each was forced — the four `*-init` Django services folded into their web pods, and the two bootstrap Jobs compose runs from the host — so only a *new* difference fails. **A `k8s` CI job** runs `k8s-lint` then `k8s-drift` on every push and PR. No cluster, no marketplace action: helm is fetched as the pinned static binary the Talos runbook already gives developers. Closes #168 ## Definition of Done - [x] Linked Gitea issue (above). - [x] Failing test committed before the implementation — the red commit reports all six real differences; the green commit declares them. - [x] Implementation makes the test pass. - [x] Conventional Commits referencing the issue (`refs #168`). - [x] CI green — awaiting the run on this PR (`make k8s-lint` and `make k8s-drift` pass locally). - [x] `docker compose up` unaffected — no service, image or compose file is touched. - [x] Docs updated — `docs/runbooks/ci.md` (job table + the one place local and CI now differ), `docs/runbooks/kubernetes-talos.md` §7/§"not ported", and ADR-0033's cost note. - [x] No ADR needed: no new dependency (python stdlib, and helm/docker were already prerequisites of the `k8s-*` targets), no boundary moved, no §8 rule bent. - [x] Not user-visible, so no demo note. ## Notes for reviewers Verified by hand that both drift classes fail the check, not just that it passes today: - bumping `OPENZAAK_TAG` in compose alone → reports `openzaak` and `oz-celery` with both image strings; - adding a workload to `values.yaml` alone → reports it by name. Deliberate limits (there is a `ponytail:` note in the script): - **Names and images only**, as sets — no per-workload env, ports or volumes. Those differ by design in four documented places, so comparing them would mean re-encoding every deviation field by field for very little more signal. - **The three observability workloads are rendered with `enabled=true`** by the check, even though both stacks default them off, so their images can't drift unwatched. - **`k8s-lint`/`k8s-drift` are not in `make ci`**, to avoid making `helm` a hard prerequisite for everyone. That is now the only local/CI difference; it's called out in `docs/runbooks/ci.md`. Follow-ups filed while reviewing the chart, not addressed here: #169 (the published docs omit every ADR after 0010 and all runbooks but `ci.md`) and #170 (the production-posture ADR #25 asked for — secrets are still plain text in `values.yaml`).Reviewed-on: #171 |
||
|
|
1dd8bd4e1b |
S-24/#25 · Helm chart + Kubernetes deployment, and Caddy for the portals (#166) (#167)
## What & why Two changes, made and verified together on a real cluster. **S-24 / #25 — a Helm chart for the platform.** One chart, `infra/helm/big-reference`, whose `values.yaml` is a near-literal transcription of `infra/docker-compose.yml`, rendered by three generic templates (Deployment, Job, Service) over a `workloads` map. Adding a service is a values edit. `make k8s-lint` renders and schema-checks the whole stack without a cluster. The issue asked for a *sketch*; this is deployed and verified end to end (see below), which is more than it asked for — the part it asked for that is **not** here is the production-posture write-up (HA, secrets, backup), see Known gaps. **#166 — Caddy replaces nginx in the portals.** nginx resolves a variable `proxy_pass` upstream itself, using only the `resolver` directive and never `/etc/resolv.conf`'s search domains. That had cost two workarounds in one script: rewriting the resolver address for rootless podman, and injecting a full FQDN so the bare `bff` name could resolve on Kubernetes. Caddy dials per request through the system resolver, so `reverse_proxy bff:8080` works on every engine unchanged; `apps/portal-nginx-resolver.sh` and the chart's `BFF_HOST` env are deleted. Closes #25 Closes #166 ## Definition of Done - [x] Linked Gitea issue (above). - [x] Failing test committed before the implementation — twice: the Caddyfile contract test before the Caddyfiles, `make k8s-lint` before the chart. - [x] Implementation makes the test pass. - [x] Conventional Commits referencing the issues (`refs #25` / `refs #166`). - [ ] CI green — awaiting the run on this PR (`make k8s-lint`, `dotnet format` and the new unit self-check pass locally; the compose e2e and mutation lanes are CI's). - [ ] `docker compose up` from a fresh clone reaches green health checks within 3 minutes — the portal images were rebuilt and verified standalone, but a full `make up` run has not been done on this branch. Please confirm in review or let CI's smoke test speak. - [x] Docs updated — `docs/runbooks/kubernetes-talos.md` (new), `frontend-decisions.md`, `demo-script.md`, and the docs that named nginx. - [x] ADR added — ADR-0033 (chart) and ADR-0034 (Caddy). - [ ] Demo note in `docs/demo-script.md` — not added: the deployment target is not a user-visible slice, and the Caddy swap is invisible to the demo script beyond the wording fix included here. ## How it was verified Brought up from scratch on a single-node Talos v1.14.0 VM (6 vCPU / 10 GB, virtio disk) under virt-manager: **29 pods ready and four bootstrap Jobs complete in under three minutes, zero restarts**, using ~4.4 GB of the VM's 10 GB. - Full Common Ground path: portal Caddy → BFF → domain → Flowable → ACL → OpenZaak + Objecten → NRC → event-subscriber → projection → public register (`INGEDIEND`, reference matching the submitted registration). - Werkbak read with an MFA'd medewerker token → 200. - The browser flow driven with Playwright against `http://localhost:30140`: secure context, `crypto.subtle` present, Keycloak form reached, login completed, **no console errors**. - Routing checked against a stub BFF: SPA fallback serves deep links, each portal proxies its own groups, and a portal does *not* proxy a neighbour's group. ## Notes for reviewers Three bugs this shook out, each fixed at the cause rather than the symptom: 1. **`command` vs `args`.** Compose's `command:` replaces the image CMD; Kubernetes' replaces the ENTRYPOINT. Transcribing one to the other broke every upstream image that relies on its entrypoint — postgres refused to run as root, Keycloak tried to exec `start-dev`. The chart now `fail`s at render time on `command`. 2. **Concurrent migrations.** Both `/setup_configuration.sh` and `/start.sh` run `manage.py migrate`; compose serialises them with `depends_on`, Kubernetes has no such edge, so the init Job and its web pod raced (`relation "zgw_consumers_service" already exists`). The four Django services now do both steps in order in the web pod — which also deletes four workloads. 3. **`emptyDir` databases are wiped by any pod-template change.** `make k8s-reseed` now also restarts `event-subscriber` and `projection-api`, which create the projection schema on start and otherwise keep writing to a schema-less database. Known gaps / follow-ups: - **Secrets.** `values.yaml` carries the dev credentials in plain text (`admin/admin`, the ZGW client secret, the two Objecten tokens) and the chart has no `Secret` objects. Fine for a laptop demo, and exactly what #25's "production posture" ADR should address — I suggest a follow-up issue rather than stretching this PR. - **No CI gate for the chart yet.** `make k8s-lint` exists but is not wired into `.gitea/workflows/ci.yaml`, and nothing enforces that the chart and the compose file stay in step. Worth a small follow-up. - **This is two slices in one PR.** They were built and verified together and the diff is entangled (the chart was written against Caddy from the start), so splitting now would mean re-creating an nginx-shaped chart to throw away. Happy to split if you'd rather. - **Rebased onto #161** (merged as #165) rather than merged, to keep the history linear. One conflict, in the `unit:` target where both branches add a self-check line — resolved by keeping both. #161's `infra/host-browser.yml` arrived with `/usr/share/nginx/html/config.json` and is fixed to `/usr/share/caddy/` inside the `feat(portals)` commit, so no commit on this branch leaves that overlay pointing at a path the images no longer have.Reviewed-on: #167 |