Files
macanhhuy d6dddbbc91
Build + push image / build-and-push (push) Successful in 1m8s
chore: remove GCP + GitLab references, migrate to Gitea registry
Replace eu.gcr.io/vnc-development image refs with gitea.saas.vnc.biz/vnciac,
swap gcr-json-key pull secret for gitea-registry, and update CI/deploy docs
from GitLab CI to Gitea Actions.
2026-08-19 17:31:05 +07:00

78 lines
10 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# AGENTS.md — vnctalk-prosody
## What this repo is
Dockerized Prosody **13.0.6** XMPP server for VNCtalk, built against **Lua 5.4** on Alpine 3.23. The Dockerfile compiles Prosody from source, applies `.patch` unified diffs to upstream core files, and layers on custom Lua modules from `vnctalk/`. There is no Lua package manager, linter, or unit-test framework; verification is image-build + an optional pytest + slixmpp integration suite against a running server.
> **Version drift warning:** `patches/README.md`, `CLAUDE.md`, and `helm/prosody/Chart.yaml` (`appVersion: 0.11.6`) still reference older Prosody versions. The **Dockerfile is the source of truth** (downloads `prosody-13.0.6.tar.gz`, `--lua-version=5.4`). `argo/prosody.yaml` overrides the helm tag to `release-13.0.6-vnc`. Trust the Dockerfile when docs disagree.
## Build & verification
- **Build:** `docker build -t <tag> .` (multi-stage Alpine; builder compiles Prosody, final stage copies `/usr/local/`).
- **Build gotcha:** `./configure --idn-library=idn` is mandatory. Prosody 0.12+ defaults to ICU, but the runtime image ships no ICU data files (`U_FILE_ACCESS_ERROR`); libidn is used instead. The builder also passes `--lua-version=5.4`.
- **Docker-compose test harness** (`docker-compose.yml`): postgres + an aiohttp mock (stands in for auth/FCM/file-share/avatar backends) + prosody. Convenience wrappers in the `Makefile`:
- `make up` — build + start postgres/mocks/prosody (run pytest from host against published ports).
- `make down` / `make logs`.
- `make test` runs the suite in the `tester` service, but `tester` is gated behind the `ci` profile (`profiles: ["ci"]`) — invoke as `docker compose --profile ci run --rm tester pytest . -v -c pytest.ini`. Easier: use `run-compose-tests.sh` (see below).
- **`run-compose-tests.sh`** is the recommended one-shot runner: creates `tests/venv`, brings up the stack, waits for prosody health, and runs the full suite from the host with all env vars set. Flags: `--no-down` (leave stack up), `--down` (tear down only). It auto-remaps telnet to 5583 if 5582 is taken (e.g. by a stale kubectl port-forward).
- **`run-tests.sh` / `run-all-tests.sh`** target an **external microlab deployment** (hardcoded hosts/creds), not the compose harness. They require an SSH tunnel to PostgreSQL (`ssh -p 60024 … -L 14322:127.0.0.1:5432`) and a `kubectl port-forward services/telnet 5582:5582 -n prosody`. Not for local image testing.
- `test.sh` is a **manual smoke test**: `./test.sh <image-tag>` runs the image with example env vars. Not automated.
- **Python integration suite** in `tests/` (pytest + slixmpp, `~86` tests across `test_01``test_12`). See `tests/README.md`, `tests/AUDIT.md`, `tests/MANUAL_TESTS.md`.
- Set up: `python3 -m venv tests/venv && source tests/venv/bin/activate && pip install -r tests/requirements.txt`
- **Always pass `-c tests/pytest.ini`** — it sets `asyncio_mode = auto`; without it collection fails with an asyncio error.
- Dry run (no server, skips live-only tests): `pytest tests/ -v --skip-live -c tests/pytest.ini`
- Single file: `pytest tests/test_05_patches.py -v -c tests/pytest.ini`
- Collect-only sanity check: `pytest tests/ --collect-only -c tests/pytest.ini`
- Against a server: set `XMPP_HOST`, `XMPP_PORT`, `XMPP_JID`, `XMPP_PASSWORD`, `XMPP_DOMAIN`, `MUC_DOMAIN`. For full coverage also `XMPP_JID2`/`XMPP_PASSWORD2` (distinct account), `REST_URL`, `BOSH_URL`, `WS_URL`, `ADMIN_TELNET_HOST`/`ADMIN_TELNET_PORT`, `PG_HOST`/`PG_PORT`/`PG_USER`/`PG_PASSWORD`/`PG_DB`, `MOCK_URL` (side-effect assertions), and `REST_USER`/`REST_PASSWORD` if `/rest` is behind HTTP Basic Auth. SSL verification is off by default (containers use self-signed certs); add `--verify-ssl` only with a real cert.
## Code layout
| Path | Purpose |
|------|---------|
| `Dockerfile` | Multi-stage build. Builder applies `patches/*.patch` to the extracted Prosody source, then `./configure --idn-library=idn --lua-version=5.4 && make install`. Final stage copies the built tree + `vnctalk/` modules + `config/`. |
| `patches/` | Unified diffs (`a/...`/`b/...` headers, paths relative to the Prosody source root) applied in the builder with `patch -p1 --fuzz=0` **before** configure. Applied via glob — **adding/removing a `.patch` needs no Dockerfile change.** `--fuzz=0` means upstream drift fails the build loudly. `patches/README.md` documents each patch's intent (but mislabels the base version — see drift warning above); `upgrade-plan.md` tracks per-version disposition. |
| `vnctalk/` | VNCtalk-original Prosody modules, copied wholesale to `/usr/local/lib/prosody/modules/`. |
| `config/` | Runtime templates and shell scripts (rendered/run at container start). |
| `tests/` | pytest suite + `mocks/` aiohttp mock service + `Dockerfile` for the tester image. |
| `helm/prosody/` | Helm chart for Kubernetes deployment (`Chart.yaml`, `values.yaml`, `templates/`). `appVersion` in `Chart.yaml` is stale; the actual image tag is set in `argo/prosody.yaml`. |
| `argo/prosody.yaml` | ArgoCD `Application` manifest — the canonical deploy config (image tag, ingress, env). Useful reference for production wiring. |
| `db-customization/` | PostgreSQL schema/migration SQL for the Prosody 13 DB (`prosody-13-migration-once.sql`, rules/triggers, no-owner variants). Applied out-of-band, not by the container. |
| `scan/` | CI artifact output (Trivy image-scan results), not source. |
| `upgrade-plan.md`, `PATCHES_AND_MODULES.md` | Reference docs tracking patch/module disposition across versions. |
| Root `*.log`, `testrun-*.md`, `m1-manual-tasks.md`, `db-change-analysis.md`, `vc-set.xml` | Working scratch / run-report artifacts from past test sessions, not source. |
### Patch vs. module — where a change belongs
- **`patches/`** for changes to *upstream* Prosody behavior (core or bundled modules: `mod_mam`, `mod_muc`, `mod_carbons`, `muc.lib.lua`, `register.lib.lua`, `hidden.lib.lua`, `mod_muc_unique`, …). Regenerate with `diff -u pristine/<path> patched/<path>` keeping the `a/<path>`/`b/<path>` header form. Document intent in `patches/README.md`.
- **`vnctalk/`** for VNCtalk-specific new functionality (`mod_vnc_*`, `mod_http_rest`, `mod_alias`, `mod_webpresence`, …).
- When adding a module of either kind, also enable it in `config/prosody.cfg.lua.template` (global `modules_enabled`, or the `modules_enabled` of the specific host/component), or it installs but stays inactive.
## Configuration
- The real config source is `config/prosody.cfg.lua.template`. At startup `startup.sh` renders it with `envsubst` to `/etc/prosody/prosody.cfg.lua`. **Edit the template, not a generated `.cfg.lua`.**
- Template variables use `${VAR}` syntax. The full set (verify here before assuming a knob doesn't exist): `prosodyDomain`, `prosodyDBhost`, `prosodyDBname`, `prosodyDBuser`, `prosodyDBpass`, `prosodyDBport`, `hybridaAuthUrl`, `fcmApiKey`, `fcm_api_url`, `del_api_url`, `fileShareBaseUrl`, `fileShareSecret`, `avatarUploadUrl`, `avatarUploadUser`, `avatarUploadPass`, `componentSecret`, `DEFAULT_JITSI_CONFERENCE`, `log_slow_events_threshold`, `SMACKS_HIBERNATION_TIME`, `C2S_STANZA_SIZE_LIMIT`, `S2S_STANZA_SIZE_LIMIT`, `PROSODY_LOG_LEVEL` (set by `startup.sh` from `PROSODY_DEBUG=true`).
- **Env-var naming gotcha:** the template uses snake_case `${fcm_api_url}` / `${del_api_url}`. `test.sh` historically passes camelCase `fcmApiUrl`/`fcmDelUrl`, which `envsubst` silently leaves unsubstituted. The compose harness uses the correct snake_case names — match the template.
- The template defines **two VirtualHosts + three Components**: `VirtualHost "${prosodyDomain}"` (HTTP-async auth), `VirtualHost "anon.${prosodyDomain}"` (anonymous auth), `Component "conference.${prosodyDomain}" "muc"` (MUC, own module list + MAM config), `Component "pubsub.${prosodyDomain}" "pubsub"`, and `Component "broadcast@${prosodyDomain}" "vnc_broadcast"`. Most module/config changes target one specific host/component, not the global list.
- `startup.sh` appends defaults to the rendered config when env vars are unset: `SMACKS_HIBERNATION_TIME` (300s; compose lowers to 10s so SMACKS-expiry tests don't wait 5 min), a random `componentSecret` (port 5347), `DEFAULT_JITSI_CONFERENCE`, `C2S/S2S_STANZA_SIZE_LIMIT` (5 MB), and `PROSODY_LOG_LEVEL`.
- The config sets `run_as_root = true` and `console_interfaces = { "*" }` / `http_interfaces = { "*", "::" }` — required because production and the compose harness run as root and expose the telnet/HTTP ports beyond loopback.
## Runtime quirks
- `startup.sh` (main `CMD`): writes TLS cert/key (from `$prosodySSLcert`/`$prosodySSLkey` env, else a baked-in dev default, overridden by `/etc/tls-update/tls.{crt,key}` if present), renders config, then runs `/usr/local/bin/prosody -F` (also tails `/var/log/prosody/prosody.log`).
- `startup-sidecar.sh` is a separate entrypoint for a static-file/redirect sidecar (`http-server` on :8080). **Not** the XMPP server; not invoked by the main `CMD`.
- `healthcheck.sh`: if `/etc/tls-update/tls.crt` differs from the loaded cert, exits **2** (not 1) to force a container restart so the new cert is picked up. Otherwise checks the admin telnet port 5582 via `check_tcp`.
- The image declares `USER prosody`, but `startup.sh` writes certs/config into root-owned `/etc/prosody`. Production and the compose harness run as root (`user: "0:0"`).
## CI / deploy
- Gitea Actions (`.gitea/workflows/deploy.yml`). `main` builds with kaniko (daemon-less) and pushes to the Gitea registry as `gitea.saas.vnc.biz/vnciac/vnctalk-prosody:sha-<short-sha>` and `:latest`. Auth via `REGISTRY_USER` / `REGISTRY_TOKEN` actions secrets.
- Kubernetes deploy is via the ArgoCD application in the `vnc-iac-env` GitOps repo (`dev/charts/vnctalk-prosody`). The in-repo `helm/prosody/` + `argo/prosody.yaml` are legacy references, not the live deploy path.
## Module conventions
- Lua 5.4. Modules follow Prosody conventions (`module:hook`, `module:open_store`, `module:get_option_string`, `module:provides`).
- Authentication is delegated to an external HTTP endpoint via `mod_auth_http_async` (`hybridaAuthUrl`) on the main VirtualHost; the global default is `internal_hashed`.
- Push notifications: `mod_vnc_fcm` (1:1) / `mod_vnc_muc_fcm` (MUC) over a configurable FCM proxy URL (`fcm_api_url`).
- `mod_http_rest` exposes `/rest` accepting `text/xml` bodies, injected as XMPP stanzas (fires `vnc-rest-message`, consumed by the `mod_carbons`/`mod_mam` patches).
- The `mod_mam` patch always stores (`shall_store → true`) and only archives stanzas with a `<body>`, because users live in the external HTTP auth backend so Prosody's `user_exists()` can't be trusted.