Build + push image / build-and-push (push) Successful in 1m8s
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.
10 KiB
10 KiB
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, andhelm/prosody/Chart.yaml(appVersion: 0.11.6) still reference older Prosody versions. The Dockerfile is the source of truth (downloadsprosody-13.0.6.tar.gz,--lua-version=5.4).argo/prosody.yamloverrides the helm tag torelease-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=idnis 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 theMakefile:make up— build + start postgres/mocks/prosody (run pytest from host against published ports).make down/make logs.make testruns the suite in thetesterservice, buttesteris gated behind theciprofile (profiles: ["ci"]) — invoke asdocker compose --profile ci run --rm tester pytest . -v -c pytest.ini. Easier: userun-compose-tests.sh(see below).
run-compose-tests.shis the recommended one-shot runner: createstests/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.shtarget 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 akubectl port-forward services/telnet 5582:5582 -n prosody. Not for local image testing.test.shis a manual smoke test:./test.sh <image-tag>runs the image with example env vars. Not automated.- Python integration suite in
tests/(pytest + slixmpp,~86tests acrosstest_01–test_12). Seetests/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 setsasyncio_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 alsoXMPP_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), andREST_USER/REST_PASSWORDif/restis behind HTTP Basic Auth. SSL verification is off by default (containers use self-signed certs); add--verify-sslonly with a real cert.
- Set up:
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 withdiff -u pristine/<path> patched/<path>keeping thea/<path>/b/<path>header form. Document intent inpatches/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(globalmodules_enabled, or themodules_enabledof the specific host/component), or it installs but stays inactive.
Configuration
- The real config source is
config/prosody.cfg.lua.template. At startupstartup.shrenders it withenvsubstto/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 bystartup.shfromPROSODY_DEBUG=true). - Env-var naming gotcha: the template uses snake_case
${fcm_api_url}/${del_api_url}.test.shhistorically passes camelCasefcmApiUrl/fcmDelUrl, whichenvsubstsilently 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", andComponent "broadcast@${prosodyDomain}" "vnc_broadcast". Most module/config changes target one specific host/component, not the global list. startup.shappends 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 randomcomponentSecret(port 5347),DEFAULT_JITSI_CONFERENCE,C2S/S2S_STANZA_SIZE_LIMIT(5 MB), andPROSODY_LOG_LEVEL.- The config sets
run_as_root = trueandconsole_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(mainCMD): writes TLS cert/key (from$prosodySSLcert/$prosodySSLkeyenv, 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.shis a separate entrypoint for a static-file/redirect sidecar (http-serveron :8080). Not the XMPP server; not invoked by the mainCMD.healthcheck.sh: if/etc/tls-update/tls.crtdiffers 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 viacheck_tcp.- The image declares
USER prosody, butstartup.shwrites 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).mainbuilds with kaniko (daemon-less) and pushes to the Gitea registry asgitea.saas.vnc.biz/vnciac/vnctalk-prosody:sha-<short-sha>and:latest. Auth viaREGISTRY_USER/REGISTRY_TOKENactions secrets. - Kubernetes deploy is via the ArgoCD application in the
vnc-iac-envGitOps repo (dev/charts/vnctalk-prosody). The in-repohelm/prosody/+argo/prosody.yamlare 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 isinternal_hashed. - Push notifications:
mod_vnc_fcm(1:1) /mod_vnc_muc_fcm(MUC) over a configurable FCM proxy URL (fcm_api_url). mod_http_restexposes/restacceptingtext/xmlbodies, injected as XMPP stanzas (firesvnc-rest-message, consumed by themod_carbons/mod_mampatches).- The
mod_mampatch always stores (shall_store → true) and only archives stanzas with a<body>, because users live in the external HTTP auth backend so Prosody'suser_exists()can't be trusted.