100 Commits
Author SHA1 Message Date
Stefan-Sanger 1a9b2262c9 fix(fcm): use dot-call for prosody.events.fire_event so cache invalidation reaches MUC
prosody.events.fire_event is a plain function (event_name, event_data), not
a method. The colon form prosody.events:fire_event(name, data) passed the
events table as event_name, so the lookup found no handlers and the
vnc-fcm-invalidate-notify-cache / vcard-cache signals were silently lost.

mod_vnc_muc_fcm hooks these via module:hook_global (which registers under
the string event name), so its notify_cache was never invalidated cross-host.
A stale empty cache entry for an MUC affiliate (left by an earlier test
before the user had a token) then suppressed FCM pushes to that affiliate,
breaking test_muc_fcm_push_to_offline_member in the full suite.

Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/11>
2026-07-23 08:40:01 +02:00
Stefan-Sanger 2252b08139 fix(fcm): pass full JID to fcm_notify and use st.clone in MUC handler
fcm_notify splits userName internally via jid_split, so callers were
double-splitting: passing jid_split(to) fed the bare node as userName
and shifted every subsequent argument by one (host→title, resource→body,
…), corrupting all notification payloads. Pass the full JID instead.

In mod_vnc_muc_fcm, replace event.stanza:clone() with st.clone() and
add the util.stanza import for robustness.

Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/11>
2026-07-22 16:33:17 +02:00
Stefan-Sanger c64346e283 fix: copy vnc_fcm_common.lua to prosody lib root so require works
Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/11>
2026-07-22 15:43:40 +02:00
Stefan-Sanger 94ee78f115 refactor(fcm): extract shared FCM logic into vnc_fcm_common.lua
- Extract ~90% duplicated code from mod_vnc_fcm and mod_vnc_muc_fcm
- Add notify_cache (300s) and vcard_cache (600s) with cross-module invalidation
- Hoist getDisplayName before MUC affiliate loop
- Defer MUC affiliate notifications via timer.add_task(0, ...)
- Remove bare_sessions diagnostic scan, dead code, and per-send option lookups
- Fix read-receipt routing and respect MUC lang preference
- Unify stale-token cleanup (NotRegistered/etc.) in both modules

Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/11>
2026-07-22 15:07:01 +02:00
Stefan-Sanger ef8c0292d6 fix: convert conditional DO rules on prosody table to triggers
PostgreSQL rejects INSERT ... ON CONFLICT ... DO UPDATE on any table
that has a conditional (WHERE) DO/DO ALSO rule or a non-NOTHING DO
INSTEAD rule, erroring with 'INSERT with ON CONFLICT clause cannot be
used with table that has INSERT or UPDATE rules'. Prosody 13's
mod_storage_sql uses ON CONFLICT upserts against the prosody kv table
whenever prosody_unique_index exists (created by these scripts), so the
five inherited conditional DO rules on prosody (cache_group_avatarids,
update_profile_queue_from_insert/_update, update_muc_remote_name,
update_room_nick_jid_map_remote) broke every kv upsert (vcard, vcard_muc,
muc_remote, config, fcmtoken, ...).

Replace those rules with AFTER INSERT / AFTER INSERT OR UPDATE
row-level triggers, which do not block ON CONFLICT. The two profile-queue
rules merge into one AFTER INSERT OR UPDATE trigger so the UPDATE branch
of an ON CONFLICT upsert is also covered (it fires AFTER UPDATE triggers,
not AFTER INSERT, when the conflict is taken).

Also drop the legacy 0.11.6 update_group_owners rule. It is logically
dead under 13.0.6 (fires on key='_affiliations', which is never written)
but PostgreSQL checks rule existence at plan time, so even a dead
conditional rule blocks ON CONFLICT. Dropping it is mandatory, not
optional as the README previously claimed.

Conversion is added to both prosody-13-new-deployment.sql (fresh
deployments, and the run_new_deployment branch of migrate.sh) and
prosody-13-rules-triggers.sql (the run_rules_triggers branch for
0.11.6->13.0 upgrades), so every helm pre/post-upgrade hook path
reaches the fix. Derived-table INSTEAD upsert rules are unchanged.

Verified against postgres:16: both scripts apply cleanly, pg_rewrite
for prosody returns 0 rows, ON CONFLICT upserts succeed, and triggers
fire on both INSERT and conflict-UPDATE branches; reproduced the
production error by re-adding the legacy rules, then confirmed the
incremental script resolves it. Idempotent re-run safe.

Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/10>
2026-07-16 06:49:46 +00:00
Stefan-Sanger b49e9bcaa1 fix: guard mod_saslauth against session destroyed during async HTTP auth
mod_auth_http_async blocks the c2s async runner on an HTTP call inside
SASL plain_test. If the client disconnects during that call,
sessionmanager.retire_session nils every session field (incl.
base_type) and marks it destroyed. When the runner resumed,
mod_saslauth crashed at sasl_process_cdata line 94 on
'sasl/'..session.base_type..'/'. Bail out when the session is gone
instead of firing the event and sending a reply to a dead connection.

Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/9>
2026-07-16 08:38:14 +02:00
Stefan-Sanger dde2e6a0e5 fix: deduplicate prosody table before creating unique index
The pre-upgrade hook failed with "could not create unique index
prosody_unique_index" because the prosody table contained duplicate
rows (same host, user, store, key). Without the unique index,
mod_storage_sql falls back to SELECT-then-INSERT instead of ON
CONFLICT upsert, which races under concurrent writes and inserts
duplicates — most commonly in the fcmtoken map store.

Add a DELETE that removes duplicate rows (keeping the last-written
row per group via ctid ordering) immediately before the CREATE UNIQUE
INDEX in both prosody-13-new-deployment.sql and
prosody-13-migration-once.sql. The DELETE is a no-op when no
duplicates exist, preserving idempotency.

Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/8>
2026-07-16 06:10:01 +00:00
Stefan-Sanger a4f17e2506 fix: cap WebSocket fragment buffer at configurable max message size
The mod_websocket continuation-frame patch accumulated fragments in an
unbounded dataBuffer with no size limit, fragment count limit, or
timeout. A buggy or malicious client sending endless continuation
frames without FIN could exhaust memory and degrade the entire server.

Add a configurable websocket_max_message_size option (default 2 MB)
that closes the connection with code 1009 ("Message too big") and
resets the buffer when exceeded. Also add wss-perf-analysis.md
documenting the WebSocket performance and drop investigation.

Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/8>
2026-07-16 06:10:01 +00:00
Stefan-Sanger 1affb3acc3 fix: use Prosody 13 get_room_from_jid API in broadcast/FCM MUC fanout
mod_vnc_broadcast and mod_vnc_fcm accessed the deprecated
prosody.hosts[host].modules.muc.rooms[to] table, removed in Prosody 13,
triggering 'Attempt to read a non-existent global rooms' warnings and
silently breaking MUC affiliation fan-out for broadcasts and push.

Replace with a version-safe get_room_from_jid() helper (rawget fallback
to .rooms for older Prosody), matching the pattern already in
mod_vcard_muc. Guard _affiliations access behind a nil room check.

Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/7>
2026-07-16 08:00:57 +02:00
Stefan-Sangerandmarge e98f9cf4c9 perf: add global LRU cache to mod_vnc_lastactivity store reads
Add a module-scoped util.cache LRU (lastactivity_cache_size default 5000,
lastactivity_cache_ttl default 300s) in front of the activity_store /
remote_activity_store fallback. Write-through on all set sites
(authentication-success, local last-session unavailable, remote
unavailable) and read-through in both IQ handlers (batch and standard
jabber:iq:last), so repeated last-activity queries for the same contacts
no longer hit the synchronous SQL driver, reducing event-loop blocking.

Also removes dead code (avatar-hash helpers, dumpTable, unused imports,
commented-out debug logging) and the unused remote avatar-update tracking.

Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/5>
2026-07-16 04:26:15 +00:00
Stefan-Sangerandmarge 658008606a Revert "perf: buffer mod_vnc_lastactivity DB writes and flush periodically"
back to original code for further analysis and improvement

This reverts commit 83e578cb94.

Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/5>
2026-07-16 04:26:15 +00:00
Stefan-Sanger 256b5fdeb1 fix: create prosody_unique_index on upgraded databases
Prosody 13's mod_storage_sql upgrade path only warns when the index is
missing (it is created only on fresh tables). On DBs upgraded from 0.11.6
the table pre-existed, so the index was never created and has_upsert_index
stayed false, disabling ON CONFLICT upserts and degrading write performance.

Add an idempotent CREATE UNIQUE INDEX IF NOT EXISTS to both the migration
and new-deployment scripts.

Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/4>
2026-07-15 19:51:02 +02:00
Stefan-Sanger 0fbcd183e3 fix: install lua-unbound to silence DNS resolver fallback warning
Prosody 13 prefers lua-unbound for DNS but the image never installed it,
causing a startup warning and a fallback to the old resolver.

Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/4>
2026-07-15 19:34:59 +02:00
Stefan-Sanger 386f36d133 fix: use DROP MAPPING instead of deleting from pg_ts_config_map
The pre-upgrade hook failed with 'permission denied for table
pg_ts_config_map' because the migration runs as prosodyDBuser (a
non-superuser), and pg_ts_config_map is a PostgreSQL system catalog that
only superusers can DELETE from.

Replace the direct 'delete from pg_ts_config_map where ...' with the
equivalent non-superuser DDL 'ALTER TEXT SEARCH CONFIGURATION ... DROP
MAPPING IF EXISTS FOR <token types>', enumerating every token type the
block re-adds. Verified against postgres:15 as a non-superuser role: the
DELETE reproduces the exact error, DROP MAPPING IF EXISTS succeeds, and
the drop+re-add round-trip is idempotent across repeated runs.

Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
2026-07-15 17:59:12 +02:00
Stefan-Sanger b51bc373d3 fix: set non-LoadBalancer services to ClusterIP
The http (5280), telnet (5582), and web2 (8080) Services were hardcoded
as NodePort, exposing them on every node's IP. Only s2s (5222/5269)
needs external exposure and remains LoadBalancer. Switch the three
internal services to ClusterIP so they are reachable only via ingress or
within the cluster. Also update the unused service.type value in
values.yaml to ClusterIP so NOTES.txt lands in the port-forward branch
instead of the stale NodePort branch.

Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
2026-07-15 17:59:12 +02:00
Stefan-Sanger 1ed6a4c129 fix: keep DB migration hook logs inspectable after deployment
Switch hook-delete-policy from hook-succeeded to before-hook-creation on
both the pre-upgrade and post-upgrade migration Jobs. hook-succeeded
deleted the Job immediately on success, making post-deploy log
inspection impossible. before-hook-creation keeps the most recent run's
Job and logs around (inspectable via kubectl logs job/<name>) and only
removes the previous Job when the next deployment fires the hook,
avoiding name conflicts and accumulation.

Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
2026-07-15 17:59:12 +02:00
Stefan-Sanger 35161b9b6d fix: resolve 3 in-container test failures in CI compose run
1. REST 404 "Unknown host: prosody": the tester reaches prosody by
   service name (http://prosody:5280), so aiohttp sends Host: prosody,
   which Prosody rejects as an unknown vhost. The auto host-header
   heuristic only overrides for IP/localhost. Set REST_HOST_HEADER=
   example.com explicitly in the tester env so HTTP routing lands on the
   example.com VirtualHost that serves mod_http_rest /rest.

2. healthcheck.sh not found: the static test_04_infra checks resolve
   ../config/healthcheck.sh (= /config/healthcheck.sh) but the tester
   image only ships /tests. Mount ./config:/config:ro so the path
   resolves inside the container.

3. telnet non-loopback banner: read only 256 bytes, capturing just the
   ASCII-art top and never the literal "Prosody" text. Bump to 1024 to
   match test_04_infra.test_telnet_banner, which passes with the larger
   read.

Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
2026-07-15 17:59:12 +02:00
Stefan-Sanger 51504f8a6f fix: correct pytest paths for tester container
The tester container uses WORKDIR /tests, so 'tests/pytest.ini' resolves
to /tests/tests/pytest.ini which does not exist, causing FileNotFoundError
in CI. Use paths relative to /tests (pytest . -c pytest.ini) for all
in-container invocations: CI job, Makefile target, tester image CMD, and
docs. Host-run scripts are unchanged (they run from repo root).

Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
2026-07-15 17:59:12 +02:00
Stefan-Sanger e1c78e7358 feat: add pre-upgrade and post-upgrade DB migration hooks
Dockerfile: add postgresql-client and bake db-customization/ SQL scripts
into the image at /vnc/db-customization/.

config/migrate.sh: detection + migration script with two modes:
- pre-upgrade: runs idempotent prosody-13-new-deployment.sql on 13.0.x
  databases; skips 0.11.6 (unsafe pre-upgrade) and new deployments.
- post-upgrade: waits for Prosody table, then runs the appropriate
  scripts — full 0.11.6->13.0.6 migration (rules-triggers + migration-once
  + new-deployment) or idempotent drift correction for 13.0.x.

Helm chart: two Job templates (db-migration-pre-upgrade.yaml,
db-migration-post-upgrade.yaml) gated by dbMigration.enabled (default
true). Both reuse the Prosody image and DB credentials from existing
values. backoffLimit: 0, hook-delete-policy: hook-succeeded.

Also tracks the db-customization SQL files (previously untracked, now
referenced by the Dockerfile ADD).

Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
2026-07-15 17:59:09 +02:00
Stefan-Sanger 86fdfbb986 docs: add database state detection guide to db-customization README
Adds a detection query set and decision tree to determine from the
database itself whether it is a new deployment, an unmigrated 0.11.6
database, an upgraded 0.11.6 database, or a clean 13.0 state — and which
script to run in each case.

Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
2026-07-15 17:58:02 +02:00
Stefan-Sanger ea043d759c docs: add README for db-customization scripts
Documents which SQL script to run for new deployments vs existing 0.11.6
database upgrades, ordering prerequisites, and what changed in the MUC
storage layout between 0.11.6 and 13.0.6.

Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
2026-07-15 17:58:02 +02:00
Stefan-Sanger 8392402301 docs: expand README with repo overview and deployment method
Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
2026-07-15 17:58:02 +02:00
Stefan-Sanger 83e578cb94 perf: buffer mod_vnc_lastactivity DB writes and flush periodically
The store :set() calls go through mod_storage_sql (LuaDBI), a blocking C
client. These hooks fire on the presence/auth hot path, so inline writes
stall the event loop under presence storms. Buffer writes in memory and
flush every 5 seconds (configurable via vnc_lastactivity_flush_interval).
The IQ handlers already read from in-memory map/remote_act_cache first,
so read consistency is preserved. Final flush on server-stopping and
host-deactivating prevents data loss on graceful shutdown.

Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
2026-07-15 17:58:02 +02:00
Stefan-Sanger efa6e73364 fix: pin http-server sidecar version
Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
2026-07-15 17:58:02 +02:00
Stefan-Sanger a2f46c99bc fix: re-add WebSocket continuation-frame support for fragmented messages
Prosody 13.0.6 removed continuation-frame (fragmented-message) support
from mod_websocket — validate_frame hard-rejects any frame with FIN=false
(close code 1003). VNCtalk clients fragment large WebSocket messages
(e.g. vCard sets with avatars >~64 KB), so the connection is silently
reset. The rejection fires on the partial-frame validation path before
handle_frame is reached, and websocket_close() does not log, so nothing
appears in prosody debug logs.

This patch removes the blanket FIN=false rejection from validate_frame
and restores the dataBuffer fragment-accumulation logic from 0.11.6 in
handle_frame: text frames (0x1) with FIN=false start a buffer,
continuation frames (0x0) append, and concatenated data is returned
only when FIN=true arrives.

Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
2026-07-15 17:58:02 +02:00
Stefan-Sanger bc5b550d9c feat: make smacks_max_unacked_stanzas configurable via env var
Default to 5 (upstream default) when SMACKS_MAX_UNACKED_STANZAS is unset.

Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
2026-07-15 17:58:02 +02:00
Stefan-Sanger 2a79ed2103 chore: remove unused mod_auth_any auth provider
mod_auth_any is never enabled in the config (auth is internal_hashed,
http_async, or anonymous) and nothing references it.

Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
2026-07-15 17:58:02 +02:00
Stefan-Sanger 5179be85a0 chore: remove unused mod_vnc_fcm_hin and mod_vnc_muc_fcm_hin modules
Neither _hin variant is enabled in the config (the active push modules
are mod_vnc_fcm for 1:1 and mod_vnc_muc_fcm for MUC). Drop the dead
files and update AGENTS.md to reference the active modules.

Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
2026-07-15 17:58:02 +02:00
Stefan-Sanger 913c6be84f test: add REST_HOST_HEADER to send Host override only for direct prosody URLs
Always sending Host: <xmpp domain> to /rest broke when REST was fronted
by an ingress (TLS hostname mismatch -> 431). Add a --rest-host-header
option (REST_HOST_HEADER env, default 'auto') that sends the XMPP domain
Host only for IP/localhost URLs where prosody needs it for vhost routing;
'none' disables, any other value is sent verbatim. Documents the option
in tests/README.md.

Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
2026-07-15 17:58:02 +02:00
Stefan-Sanger 5dca59c4c1 fix(dockerfile): verify prosody source tarball SHA256 on download
Pin the version and expected SHA256 as build ARGs and verify the
download with sha256sum -c so a tampered or corrupt source download
fails the build loudly. Also drops the noisy tar -v and removes the
tarball after extraction.

Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
2026-07-15 17:58:02 +02:00
Stefan-Sanger fa5220906e ci: add test stage running docker-compose suite on non-main branches
Bumps the base image to docker:24.0 (needed for Usage:  docker compose [OPTIONS] COMMAND

Define and run multi-container applications with Docker

Options:
      --all-resources              Include all resources, even those not
                                   used by services
      --ansi string                Control when to print ANSI control
                                   characters ("never"|"always"|"auto")
                                   (default "auto")
      --compatibility              Run compose in backward compatibility mode
      --dry-run                    Execute command in dry run mode
      --env-file stringArray       Specify an alternate environment file
  -f, --file stringArray           Compose configuration files
      --parallel int               Control max parallelism, -1 for
                                   unlimited (default -1)
      --profile stringArray        Specify a profile to enable
      --progress string            Set type of progress output (auto,
                                   tty, plain, json, quiet)
      --project-directory string   Specify an alternate working directory
                                   (default: the path of the, first
                                   specified, Compose file)
  -p, --project-name string        Project name

Management Commands:
  bridge      Convert compose files into another model

Commands:
  attach      Attach local standard input, output, and error streams to a service's running container
  build       Build or rebuild services
  commit      Create a new image from a service container's changes
  config      Parse, resolve and render compose file in canonical format
  cp          Copy files/folders between a service container and the local filesystem
  create      Creates containers for a service
  down        Stop and remove containers, networks
  events      Receive real time events from containers
  exec        Execute a command in a running container
  export      Export a service container's filesystem as a tar archive
  images      List images used by the created containers
  kill        Force stop service containers
  logs        View output from containers
  ls          List running compose projects
  pause       Pause services
  port        Print the public port for a port binding
  ps          List containers
  publish     Publish compose application
  pull        Pull service images
  push        Push service images
  restart     Restart service containers
  rm          Removes stopped service containers
  run         Run a one-off command on a service
  scale       Scale services
  start       Start services
  stats       Display a live stream of container(s) resource usage statistics
  stop        Stop services
  top         Display the running processes
  unpause     Unpause services
  up          Create and start containers
  version     Show the Docker Compose version information
  volumes     List volumes
  wait        Block until containers of all (or specified) services stop.
  watch       Watch build context for service and rebuild/refresh containers when files are updated

Run 'docker compose COMMAND --help' for more information on a command. v2) and
adds a test:compose job that builds the stack, waits for prosody health,
runs the slixmpp suite in the tester container, and emits a junit report.
Runs on merge_request_event and non-main branch pipelines.

Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
2026-07-15 17:58:02 +02:00
Stefan-Sanger e19cc05403 feat(helm): mount credentials from Secret and set per-container resources
- chart: add secretEnv (existingSecret + keys) rendered as secretKeyRef in
  both containers; add resourcesProsody/resourcesSidecar defaults with
  dedicated requests and limits via a containerResources helper
- argo: move prosodyDBpass/fcmApiKey/fileShareSecret/avatarUploadPass out of
  env into secretEnv referencing a prosody-secrets Secret; set dedicated
  resource requests+limits per container
- argo: add prosody-secrets.example.yaml ArgoCD Application (with a warning
  to use Sealed Secrets / External Secrets / SOPS instead of plaintext)
- chart fixes: bump stale appVersion 0.11.6 -> 13.0.6; fix malformed service
  block in values.yaml

Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
2026-07-15 17:58:02 +02:00
Stefan-Sanger 3918ec59e9 fix: add example app template for argocd
Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
2026-07-15 17:58:02 +02:00
Stefan-Sanger 2ae1f8e480 import helm chart
Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
2026-07-15 17:58:02 +02:00
Stefan-Sanger 5572902aac docs: reconcile AGENTS.md with Prosody 13.0.6 + Lua 5.4 and current tooling
Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
2026-07-15 17:58:02 +02:00
Stefan-Sanger 33d17d53cc feat: add PROSODY_DEBUG env var for debug logging
Set PROSODY_DEBUG=true to switch the prosody.log level from info to
debug. This makes stanza-too-large rejections and XML parse errors
visible — both are logged at debug level and otherwise invisible.

Usage in k8s:
  env:
  - name: PROSODY_DEBUG
    value: "true"

Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
2026-07-15 17:58:02 +02:00
Stefan-Sanger d51c68c0b4 feat: add C2S/S2S_STANZA_SIZE_LIMIT env vars (default 5MB)
Add c2s_stanza_size_limit and s2s_stanza_size_limit to the config
template, backed by C2S_STANZA_SIZE_LIMIT and S2S_STANZA_SIZE_LIMIT
env vars. Both default to 5242880 (5MB) when unset, set in startup.sh.
The compose harness sets them explicitly.

Prosody 13.0.6 defaults are 256KB (c2s) and 512KB (s2s), which are too
small for large file-transfer invitations and Jitsi meet sessions.

Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
2026-07-15 17:58:02 +02:00
Stefan-Sanger 5604170914 docs: add comprehensive Prosody 13.0.6 test run report
Combined results from compose harness (80 passed, 6 skipped) and external
deployment (50 passed, 36 skipped). 81 unique tests passed across both
runs, 0 failures. 5 remaining skips are config/infrastructure prerequisites,
not regressions. All 81 passed tests described with what they verify.

Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
2026-07-15 17:58:02 +02:00
Stefan-Sanger aa822329dd test: carbon-copied REST test uses same-bare-JID second resource
The test was skipping because it depended on the second_client fixture,
which uses XMPP_JID2 (a distinct account). Carbons require both
resources to share the same bare JID.

Rewrite to create a second VNCXmppClient inline with the same bare JID
as xmpp_client but a different resource (/carbon-<random>), so the test
runs regardless of whether XMPP_JID2 is configured or distinct.

Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
2026-07-15 17:58:02 +02:00
Stefan-Sanger 015c554d30 docs: add M3 test run report
Compose harness: 80 passed, 6 skipped, 0 failed.
External deployment: 61 passed, 25 skipped, 0 failed.
All skips are infrastructure prerequisites, not M3 regressions.

Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
2026-07-15 17:58:02 +02:00
Stefan-Sanger b87e6b790d feat: run-all-tests.sh auto-starts PG tunnel and telnet port-forward
Check if the SSH tunnel to PostgreSQL (port 14322) and the kubectl
port-forward for telnet (port 5582) are active before running the
testsuite. Start them automatically if missing. Clean up the
kubectl port-forward on exit if we started it.

Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
2026-07-15 17:58:02 +02:00
Stefan-Sanger 26e7512b24 feat: upgrade Prosody 0.12.6 → 13.0.6 (milestone 3)
Bump Dockerfile to prosody-13.0.6; all 8 patches re-ported against 13.0.6.

Re-ported patches (3 changed, 5 applied with offset):
- hidden.lib.patch: 13.0 uses module:may() instead of um_is_admin; changed
  to 'if restrict_public then' (same intent: hide option for everyone)
- mod_muc.patch: 13.0 added restrict_pm between register and
  presence_broadcast; updated hunk 1 context
- mod_muc_unique.patch: 13.0 uses 'require "prosody.util.stanza"'
  (namespaced); updated context
- muc.lib, mod_carbons, mod_mam, mod_muc_mam, register.lib: applied
  with line offsets, no re-port needed

Config changes:
- Remove mod_posix from modules_enabled (13.0 absorbed signal handling,
  pidfile, and run_as_root check into core util/startup.lua)
- Move pubsub from modules_enabled to Component (13.0 requires pubsub
  to be loaded as a component, not a module)

Test fix:
- test_muc_fcm_push_to_offline_member: wait for count=2 captures instead
  of 1 — mod_vnc_muc_fcm pushes to ALL affiliated members (including
  sender, because it can't see main-host sessions from the MUC
  component); the test was racing on which push arrived first

Verified: prosodyctl check config passes; compose-harness testsuite
green (80 passed, 6 skipped, 0 failed).

Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
2026-07-15 17:58:02 +02:00
Stefan-Sanger 7a369a489e docs: mark M2 complete — external testsuite passed
Update M2 status to reflect both compose-harness (80 passed, 6 skipped,
0 failed) and external testsuite results (48 passed, 30 skipped — all
skips are infrastructure prerequisites). test_vcard_fallback now skipped
pending mod_vnc_vcard_fallback enablement.

Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
2026-07-15 17:58:02 +02:00
Stefan-Sanger 3ed7aba56b feat: add run-all-tests.sh — single-invocation external testsuite
Same env vars as run-tests.sh but runs all test files in one pytest
call for a unified summary. Use run-tests.sh for selective per-file
runs.

Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
2026-07-15 17:58:02 +02:00
Stefan-Sanger c1b46d2814 revert: keep run-tests.sh with per-file pytest invocations
Revert to the original per-file invocation style — it allows running
tests selectively by commenting out individual lines.

Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
2026-07-15 17:58:02 +02:00
Stefan-Sanger 7f7c087c16 test: skip test_vcard_fallback (mod_vnc_vcard_fallback not enabled in config)
The module exists in vnctalk/ but is not listed in modules_enabled in
the config template. The test previously passed on external deployments
by coincidence — the test users already had vCards with FN from real
usage. On the compose harness with a fresh DB, the test fails because
nothing generates a vCard.

Add @pytest.mark.skip with a reason pointing to the missing module.
Simplify run-tests.sh to a single pytest invocation (was 12 separate
calls). Update m1-manual-tasks.md §3.5 to reflect the skip.

Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
2026-07-15 17:58:02 +02:00
Stefan-Sanger 43a9d7ec57 feat: add run-compose-tests.sh — one-command compose harness testsuite
Brings up the docker-compose stack (postgres + mocks + prosody), waits
for prosody to become healthy, and runs the full pytest suite with all
env vars set so tests that need MOCK_URL, PG, BOSH/WS, telnet, etc. are
not skipped.

Auto-detects if port 5582 is already in use (e.g. kubectl port-forward)
and remaps the telnet host port to 5583 via the TELNET_HOST_PORT env var
in docker-compose.yml.

Usage:
  ./run-compose-tests.sh              # up + test + down
  ./run-compose-tests.sh --no-down    # leave stack running
  ./run-compose-tests.sh --down       # just tear down

Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
2026-07-15 17:58:02 +02:00
Stefan-Sanger bce258107e feat: upgrade Lua 5.2 → 5.4 (milestone 2)
Swap all lua5.2-* Alpine packages to lua5.4-* in both Dockerfile stages
and add --lua-version=5.4 to ./configure.

Dropped packages:
- lua5.2-bitop: Prosody's util.bitcompat uses util.bit53 (native Lua
  5.3/5.4 bitwise operators) when bit32 is unavailable
- lua5.2-lpeg_patterns, lua5.2-rapidjson, lua5.2-redis: not required by
  any require in Prosody 0.12.6 or any vnctalk module
- luarocks5.2: installed but never used
- Duplicate lua5.2-socket entry: removed

Code audit for 5.2→5.4 breakage: clean.
- No bit32/bitop usage in vnctalk modules
- Every Prosody file using unpack has 'local unpack = table.unpack or
  unpack' (resolves to table.unpack on 5.4)
- No string.format('%d', float) patterns in vnctalk modules

Verified: image builds, prosodyctl check config passes, compose-harness
testsuite green (80 passed, 5 skipped — identical to M1).

Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
2026-07-15 17:58:02 +02:00
Stefan-Sanger fa27f48e85 docs: mark M1 complete — telnet console + external testsuite passed
Update upgrade-plan.md to reflect:
- M1 header:  COMPLETE (was  IMPLEMENTED with manual tasks pending)
- Step 5 (DB): N/A for PostgreSQL — upgrade_table is MySQL-only
- Step 6 (Verify):  Done — external testsuite run successful
- Step 7 (Telnet):  Done — manual test passed
- Phase 0 item 3 (DB snapshot): N/A for PostgreSQL

Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
2026-07-15 17:58:02 +02:00
Stefan-Sanger ca082d39fd fix: complete M1 — re-add run_as_root, fix stale patch tests, document manual tasks
Three changes to complete the repo-level work for Milestone 1 (0.11.6 →
0.12.6) plus a howto for the remaining manual/external tasks:

1. config/prosody.cfg.lua.template: re-add run_as_root = true. Production
   and the compose harness run as root (startup.sh writes into root-owned
   /etc/prosody/). Without it, mod_posix calls prosody.shutdown() during
   startup, which deactivates c2s (port 5222) before the shutdown itself
   errors out (prosody.main_thread is nil during module init), leaving
   Prosody running without c2s.

2. tests/test_08_image_patches.py: replace 3 stale patch-marker entries
   that checked for patches M1 intentionally dropped (moduleapi,
   mod_admin_telnet, muc.lib dumpTable) with markers that verify their
   config-based replacements (console_interfaces, http_interfaces) and
   the storagemanager.open() rewrite in mod_vnc_muc_fcm.lua.

3. upgrade-plan.md: update M1 status to reflect the post-M1 fixes
   (run_as_root, default_storage, stale tests), mark manual steps (DB
   migration, telnet console regression, external testsuite) with
   cross-references to m1-manual-tasks.md, and correct 0.12.5 → 0.12.6
   throughout.

4. m1-manual-tasks.md: new file documenting the three manual tasks that
   require external infrastructure — DB schema migration (one-way, with
   rehearse-on-copy procedure), telnet console regression test (0.12
   reimplemented the console on mod_admin_shell), and external testsuite
   run against a dev deployment.

Verified: compose-harness testsuite — 80 passed, 5 skipped, 1 pre-existing
failure (test_vcard_fallback: mod_vnc_vcard_fallback not enabled in config,
unrelated to M1).

Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
2026-07-15 17:58:02 +02:00
Stefan-Sanger 32d67502a9 fix: re-add default_storage = "sql" removed in M1 upgrade
The M1 upgrade (0ea4d0a) removed default_storage = "sql" as seemingly
redundant with storage = "sql". However, the MUC component sets
storage = { muc_log = "sql" } (a table), and storagemanager.get_driver
falls back to default_storage (or "internal") for stores not listed in
the table. Without default_storage = "sql", the kick store on the MUC
component falls back to internal storage, whose archive driver requires
stanza objects — mod_vnc_track_kicks passes a plain string, causing
"unsupported-datatype" errors and kick data not being persisted.

Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
2026-07-15 17:58:02 +02:00
Stefan-Sanger 481e1ef069 docs(tests): document docker-compose harness, DB import, and local-container runs
Extend tests/README.md with:
- Running with docker-compose: make test one-shot, host-run flow, mock
  capture/log inspection, teardown.
- Importing an existing database into the compose postgres (psql/pg_restore,
  fresh-volume flow, auth-backend caveat).
- Running against a standalone local prosody container (build + docker run,
  port mapping, optional separate mock for side-effect tests).
- Updated env table (MOCK_URL, SMACKS_HIBERNATION_TIME), test coverage table
  (test_08-12), prerequisites (tests/requirements.txt), and notes reflecting
  the new healthcheck execution, REST Host header, and XMPP_HOST/PORT fix.

Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
2026-07-15 17:58:02 +02:00
Stefan-Sanger 2b798bf583 test(harness): add docker-compose stack, mocks, and extend suite per test-improvement plan
Implements all phases of test-improvement.md:

- docker-compose.yml: postgres + aiohttp mocks + prosody + optional tester,
  using exact template placeholder names (fixes latent fcm_api_url/del_api_url
  envsubst bug).
- tests/mocks: single aiohttp backend (auth, FCM, delfile, avatar, file-share)
  with /__requests capture API and /__fcm_error for prune tests.
- tests/Dockerfile + tests/requirements.txt: tester image.
- conftest: mock_client fixture, --mock-url; VNCXmppClient now honors
  XMPP_HOST/PORT (slixmpp was SRV-resolving the JID domain); RESTInjector
  sends Host: <domain> (prosody routes HTTP by Host header).
- test_08_image_patches: docker-exec grep of every patched upstream file.
- test_09_http_sideeffects: FCM (1:1 + MUC), delfile, vcard-avatar, receipts.
- test_10_smacks: enable/ack, resume-replay, hibernation-expiry (offline
  variant xfail until fork is replaced by upstream mod_smacks_offline).
- test_11_smokes: filter_chatstates, idlecompat, http_altconnect, webpresence,
  admin-telnet non-loopback.
- test_12_image_runtime: http_upload slot handshake, healthcheck exit-2,
  no-residual-placeholder config check.
- test_06_postgres: real kick-row assertion via unregister IQ.
- test_02_muc: vcard_muc get/set; test_03_vnctalk: muc_hook non-joined affiliate.
- startup.sh + template: SMACKS_HIBERNATION_TIME as a proper global config var
  (default 300) so SMACKS expiry tests can lower it.
- Makefile (make up/test/down/logs) and run-tests.sh updated.

Validated end-to-end against the compose stack: 81 passed, 1 xfailed,
1 pre-existing vcard_fallback failure (unrelated), 3 skipped.

Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
2026-07-15 17:58:02 +02:00
Stefan-SangerandClaude Opus 4.8 54ca4e1877 fix(tests): correct module-load detection tests (test_07)
- mod_vnc_lastactivity: the jabber:iq:last handler returns <forbidden> when
  the query has no 'to'; send it to another existing user's bare JID and
  assert the result carries a 'seconds' attribute
- set body via msg["body"] and do not await message send() (returns None)
- use unique uuid room names instead of a fixed duplicated localpart
- unlock the freshly-created (locked) room with configure_muc before a
  second user joins / is affiliated
- the unregister IQ is fire-and-forget (no reply); tolerate IqTimeout rather
  than failing the kick-tracking smoke test

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
2026-07-15 17:58:02 +02:00
Stefan-SangerandClaude Opus 4.8 98c518b270 fix(tests): rewrite postgres tests against real mod_storage_sql schema
Prosody keeps every store in just two tables — prosody (keyval/map) and
prosodyarchive (archive) — distinguished by a `store` column. The previous
tests looked for separate tables named like %muc_log%, %kick%, %activity%,
which never exist, so they failed.

- check stores via the `store` column in prosody/prosodyarchive, not by
  table name: muc_log + kick are archive stores, activity + vcard are
  keyval stores (matching the modules' open_store calls)
- assert the two real tables (prosody, prosodyarchive) exist
- verify MUC archives are stored under the conference component host
- store_user inversion: 'key' is the generated archive UID, not the message
  id, so match the REST-injected message on value LIKE and then assert the
  owning 'user' is the sender and 'with' is the recipient

Verified against the live database (schema and sample rows inspected).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
2026-07-15 17:58:02 +02:00
Stefan-SangerandClaude Opus 4.8 23a0c75f33 fix(tests): bound the pg_connection fixture connect with a timeout
A half-open PostgreSQL tunnel accepts TCP but never completes the PG
handshake; asyncpg.connect() with no timeout then hangs the entire
test_06 suite indefinitely. Wrap connect in wait_for(timeout=10) and skip
with a clear message when the DB is unreachable, and only close the
connection in the finally if it was actually established (the previous
unconditional close raised NameError when connect failed).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
2026-07-15 17:58:02 +02:00
Stefan-SangerandClaude Opus 4.8 ed2d5db342 fix(tests): correct patch-contract tests (test_05)
- set body via msg["body"] / read via msg["body"]; do not await message
  send() (returns None in slixmpp)
- str(msg["from"]) / str(pres["from"]) before .startswith (JID not str)
- mod_muc_unique: query a bare JID on the MUC component (a room JID), not a
  user on the main host. The item-not-found handler is registered on the
  component; a query to the user host is merely service-unavailable.
- offline-affiliate test: unlock the freshly-created room with configure_muc
  before setting affiliations

Verified the portmanager network_default_read_size patch end-to-end: chat
bodies up to 12000 bytes are delivered intact.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
2026-07-15 17:58:02 +02:00
Stefan-SangerandClaude Opus 4.8 dca5a6ec11 fix(tests): correct vnctalk extension tests (test_03)
conftest:
- send initial presence after connect so the server routes directed
  messages to the resource (chats to a bare JID otherwise go to offline
  storage, breaking the timestamp/receipt tests)
- configure_muc: include FORM_TYPE on non-empty config submits, else
  Prosody rejects them ("Form is not of type room configuration")

test_03_vnctalk:
- set body via msg["body"] and do not await presence/message send()
- read body via msg["body"], not msg.body
- replace nonexistent slixmpp.jid.nodeprep / slixmpp.util.id.short with uuid
- disco_info form lookup uses .// (form nested under <query>)
- test_broadcast_component rewritten to exercise real fanout: the
  component is message-only (no disco), so post a <vncTalkBroadcast> with a
  <to> recipient and assert that recipient receives the cast copy
- config-change broadcast test: unlock the room first, trigger via a real
  config submit (not a subject change), and catch the bodyless
  <x xmlns='xmpp:vnctalk:update'> with a low-level handler (slixmpp's
  message event needs a <body>)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
2026-07-15 17:58:02 +02:00
Stefan-SangerandClaude Opus 4.8 ec342114e1 fix(tests): correct MUC test client API misuse and contracts
conftest:
- presence.send()/message.send() return None in slixmpp; do not await them
- JID objects are not str; use str(pres["from"]) before .startswith
- disco_info/disco_items take a timeout so a non-responding server fails
  fast instead of hanging the suite
- query_mam_and_collect takes a `to` arg to query a MUC archive (MUC MAM
  lives at the room, not the user)
- add configure_muc() to submit the owner config form; a freshly-created
  Prosody room is locked until configured and other users cannot join

test_02_muc:
- set body via msg["body"], not msg.body (the latter sets a Python attr
  and produces a bodyless stanza that is neither reflected nor archived)
- MUC MAM test queries the room and matches the inner forwarded message by
  local name (Prosody may omit xmlns='jabber:client')
- unlock rooms with configure_muc before a second user joins / is affiliated
- broadcast test rewritten as test_muc_broadcast_strips_spoofed_stanza_id:
  the real contract is anti-spoofing (a client-injected by-room stanza-id is
  stripped) while the room still adds its own legitimate XEP-0359 stanza-id
- unregister IQ handler is fire-and-forget (sends no reply); tolerate the
  IqTimeout and assert the side effect (affiliation removed)
- hidden-override test skips when the server does not restrict public rooms
- disco_info form lookups use .// (form is nested under <query>)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
2026-07-15 17:58:02 +02:00
Stefan-SangerandClaude Opus 4.8 c05bb9aadb fix(muc): serialize e2e roominfo as string in disco#info
mod_vnc_e2ehints put the raw boolean returned by get_e2e() (false when
unset) into the disco#info roominfo formdata. muc#roominfo_e2e is a
text-single field, and util.dataforms/util.stanza cannot serialize a
boolean field value, so room:get_disco_info() raised an error and the
server silently dropped the disco#info reply for every existing room
(confirmed at the wire level: non-existent rooms returned item-not-found,
existing rooms returned nothing). Coerce the value to a string, matching
the working mod_vnc_muc_data pattern. get_e2e() itself is left returning a
boolean since the muc-config-form boolean field needs it.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
2026-07-15 17:58:02 +02:00
Stefan-SangerandClaude Opus 4.8 9239b41e47 fix(tests): capture MAM results via low-level handler, not message event
slixmpp's high-level "message" event only fires for stanzas with a
top-level <body> (matcher '{jabber:client}message/{jabber:client}body').
MAM result wrappers (<message><result xmlns='urn:xmpp:mam:2'>...) have no
<body> of their own, so the event never fired and the MAM tests saw zero
results even though the server correctly returned them (<fin complete>).

Capture results with a low-level Callback + MatchXPath on the result
element instead, the same mechanism slixmpp's own xep_0313 plugin uses.
Also filter MAM queries by a start timestamp so a large archive does not
push fresh messages off the first page, and match the inner forwarded
<message> by local name to tolerate Prosody omitting xmlns='jabber:client'.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
2026-07-15 17:58:02 +02:00
Stefan-Sanger a4388ecc88 fix(tests): poll MAM for REST-injected messages instead of single sleep
Archiving triggered by REST injection is asynchronous: the HTTP endpoint
returns 201 before archive:append necessarily completes.  A single 1s sleep
was often too short, causing flaky failures even though the message was
present in the database moments later.

- Add _poll_mam_for_id helper that queries MAM up to 10 times with 1s
  intervals until the target message id appears
- Replace fixed sleeps in both REST MAM roundtrip tests with polling
- Improves reliability on slower or more loaded Prosody instances

Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
2026-07-15 17:58:02 +02:00
Stefan-Sanger bdc17cd614 fix(tests): remove 'with' filter from REST MAM roundtrip queries
For REST-injected messages, mod_mam.lua's patched message_handler sets
both store_user and the 'with' field to the sender's JID (because c2s is
false for REST and the vnc_rest branch only overrides store_user, not
'with'). Filtering by recipient to_jid therefore returns no results.

- Remove with_jid=to_jid from both REST MAM roundtrip tests
- Query the full sender archive and scan for the message id instead
- This is more robust regardless of the 'with' field semantics

Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
2026-07-15 17:58:02 +02:00
Stefan-Sanger 5c47d578f4 fix(tests): add FORM_TYPE to MAM query data form
XEP-0313 requires the MAM query data form to include a hidden FORM_TYPE
field with value 'urn:xmpp:mam:2'. Without it, Prosody's dataform
validation may reject or ignore the 'with' filter, causing the query to
return empty results even when messages exist in the archive.

- Introduce _add_mam_query_form helper that always injects FORM_TYPE
- Update query_mam and query_mam_and_collect to use the helper
- Also support start/end filters for completeness

Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
2026-07-15 17:58:02 +02:00
Stefan-Sanger 4367862e41 fix(tests): MAM <fin> is in IQ response, not a message
Prosody's mod_mam sends <result> elements as individual messages but the
<fin> element inside the IQ response stanza. The old code waited for a
<message> containing <fin>, which never arrives, causing TimeoutError.

- Remove on_mam_fin message handler
- Use iq.send() timeout instead of waiting for a message <fin>
- Add 0.5s grace period after IQ response for trailing <result> messages
- Clean up only the message handler in finally

Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
2026-07-15 17:58:02 +02:00
Stefan-Sanger 223dd7c197 fix(tests): split server and account disco info assertions
mod_mam.lua advertises urn:xmpp:mam:2 and urn:xmpp:sid:0 via the
account-disco-info hook (user bare JID), not on the server domain.
The previous test incorrectly expected them from the server domain.

- test_disco_info_server: only assert basic disco#info / disco#items
- test_disco_info_account: new test querying bare JID for MAM + sid

Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
2026-07-15 17:58:02 +02:00
Stefan-Sanger 1133b6616a fix(tests): use stdlib xml.etree and slixmpp 1.16 IQ kwargs
slixmpp 1.16 uses stdlib xml.etree.ElementTree internally, not lxml.
Using lxml elements with slixmpp stanzas causes multiple TypeErrors:

- iq.append(lxml_element) -> 'Cannot append ... to a stanza'
- ET.SubElement(iq.xml, ...) -> 'expected lxml.etree._Element, got
  xml.etree.ElementTree.Element'

Also fix make_iq_get/make_iq_set kwargs: slixmpp 1.16 uses 'ito'/'ifrom'
instead of 'to'/'from'.

- Replace all 'from lxml import etree as ET' with
  'import xml.etree.ElementTree as ET' in test files
- Replace make_iq_get(to=...) -> make_iq_get(ito=...)
- Replace make_iq_set(to=...) -> make_iq_set(ito=...)
- Leave lxml usage in non-slixmpp contexts unchanged (none found)

Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
2026-07-15 17:58:02 +02:00
Stefan-Sanger f7f3117db7 fix(tests): remove obsolete process() call and update REST non-XML assertion
- slixmpp 1.16 (asyncio) has no process() method; connect() already
  schedules background processing. Remove the call that caused
  AttributeError: 'VNCXmppClient' object has no attribute 'process'
- REST endpoint returns 422 (not 415) for invalid XML; accept both

Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
2026-07-15 17:58:02 +02:00
Stefan-Sanger 0e92f27607 fix(tests): correct slixmpp 1.16 connect() usage in VNCXmppClient
slixmpp 1.16.0 connect() is not a coroutine; it returns an asyncio.Future
and takes (host, port) kwargs, not (address, use_ssl). The previous code
awaited connect() with wrong args causing TypeError inside the async fixture,
which pytest-asyncio surfaced as ERROR at setup.

- Pass host/port/ssl_context to super().__init__() so XMLStream stores them
- Remove manual connect_address and use_ssl tracking
- async_connect: simply await self.connect() with no args (host/port already
  configured in __init__)
- Keep ssl_context creation with verify_mode=CERT_NONE for self-signed certs

Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
2026-07-15 17:58:02 +02:00
Stefan-Sanger 6c390320bb fix(tests): use @pytest_asyncio.fixture for async fixtures
pytest-asyncio 1.4 with asyncio_mode=auto requires async fixtures to be
decorated with @pytest_asyncio.fixture instead of @pytest.fixture.
Without this, async generator fixtures raise AssertionError during setup
at plugin.py:558, causing ERROR before any test code runs.

- Add import pytest_asyncio
- Replace @pytest.fixture with @pytest_asyncio.fixture for xmpp_client,
  second_client, and pg_connection async fixtures
- Leave sync fixtures (xmpp_config, rest_injector) unchanged

Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
2026-07-15 17:58:02 +02:00
Stefan-Sanger bd336c7b44 fix(tests): disable TLS cert verification by default for integration tests
Prosody containers use self-generated self-signed certs. slixmpp with
use_ssl=True verifies certificates by default, causing
SSLCertVerificationError and pytest ERROR during fixture setup.

- VNCXmppClient: add verify_ssl parameter (default False) that creates
  an ssl.SSLContext with verify_mode=CERT_NONE when disabled
- conftest.py: add --verify-ssl CLI option / VERIFY_SSL env var;
  pass verify_ssl through xmpp_config to both client fixtures
- docs: document --verify-ssl in README.md and AGENTS.md

Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
2026-07-15 17:58:02 +02:00
Stefan-Sanger a0f485d248 test: add HTTP Basic Auth support for REST injection tests
The /rest endpoint is typically protected by a reverse proxy. The
RESTInjector helper now accepts optional auth_user/auth_password and
sends an Authorization: Basic header when configured.

- conftest.py: add --rest-user/--rest-password CLI options and env vars;
  update RESTInjector to include Basic auth headers
- test_01_core.py: refactor TestRestInjection to use the authenticated
  rest_injector fixture instead of raw aiohttp calls
- tests/README.md + AGENTS.md: document REST_USER/REST_PASSWORD

Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
2026-07-15 17:58:02 +02:00
Stefan-Sanger 9be6241a55 test: cover remaining AUDIT gaps — presence exclusion, hidden override, store_user SQL, module load detection
- test_02_muc.py: add test_muc_mam_presence_not_archived (negative assertion
  that presence stanzas are excluded from MUC MAM) and
  test_hidden_lib_rejects_public_override (config form absence + raw override
  submission with xfail for admin accounts)
- test_06_postgres.py: add TestPostgresStoreUserInversion which injects via
  REST and queries the archive table directly to assert the 'user' column is
  the sender; add TestPostgresKickStore and TestPostgresActivityStore for
  mod_vnc_track_kicks and mod_vnc_lastactivity store tables
- test_07_module_load.py: new file with smoke tests for the five previously
  zero-coverage modules (lastactivity IQ, delfile message hook, remotemucstore
  message hook, remotemucinvite event, track_kicks event)
- MANUAL_TESTS.md: expand mod_auth_http_async section with mock-HTTP-server
  procedure; add container build verification steps
- AUDIT.md: revise verdict to 'adequate for upgrade safety'; update all
  coverage tables to reflect 55 tests across 7 files

Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
2026-07-15 17:58:02 +02:00
Stefan-Sanger ccd30db61c updated audit
Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
2026-07-15 17:58:02 +02:00
Stefan-Sanger c70383ef97 test: enhance suite to cover AUDIT gaps, add PostgreSQL tests, manual docs
- conftest.py: add second distinct JID support (--xmpp-jid2), REST injector
  helper, MUC join/leave/destroy helpers, PostgreSQL connection fixture
- test_01_core.py: add REST->MAM roundtrip, REST->carbons roundtrip,
  non-roster archive verification (shall_store=true contract)
- test_02_muc.py: add room hidden-by-default test, MUC MAM content
  verification, stanza-id stripping, unregister IQ affiliation removal,
  fix automember to require distinct account (xfail otherwise)
- test_03_vnctalk.py: convert pytest.skip on IqError to pytest.fail,
  add open_host_store smoke test via FCM token IQ, add E2E hints test
- test_05_patches.py: new file covering patch behavioral contracts from
  AUDIT.md: unique IQ bare-JID, hidden lib, large stanza / portmanager,
  self-unavailable routing, offline affiliate broadcast
- test_06_postgres.py: new file with PostgreSQL schema and column checks
  for archive, muc_log, vcard tables
- MANUAL_TESTS.md: new file with step-by-step procedures for contracts
  that require DB inspection, federation, or container internals
- AGENTS.md + tests/README.md: update docs with new env vars, deps,
  and run instructions

Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
2026-07-15 17:58:02 +02:00
Stefan-Sanger 2046867241 docs: add AGENTS.md, patch analysis, and pytest integration suite
- Add AGENTS.md with repo-specific conventions, build steps, and quirks
- Add PATCHES_AND_MODULES.md documenting every upstream deviation
- Add tests/ with pytest/slixmpp integration suite for core, MUC,
  vnctalk extensions, and infrastructure verification
- Include pytest.ini and .gitignore

Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
2026-07-15 17:58:02 +02:00
Stefan-SangerandClaude Fable 5 bdb9aed9e3 feat: upgrade prosody 0.11.6 -> 0.12.6 (milestone 1)
Re-port all source patches onto 0.12.6; three are gone entirely:
moduleapi (the two vnc_muc_fcm modules call core.storagemanager
directly now), mod_admin_telnet and portmanager (replaced by
console_interfaces/http_interfaces config). The muc.lib fork keeps its
four functional changes including the externally consumed
muc-config-sub-mitted event; the operator-precedence hunk was fixed
upstream. mod_muc_mam shrinks to keep-archive-on-room-destroy since
muc_log_expires_after="never" disables cleanup upstream in 0.12.

Delete the bundled mod_smacks fork and the no-op mod_smacks_offline;
core 0.12 smacks supersedes them (options audited, dead smacks_max_old
corrected to smacks_max_old_sessions).

Config/startup: drop legacyauth, run_as_root, daemonize; bosh_ports ->
http_ports; cross_domain_* -> http_cors_override; randomize
component_secret at startup (env-overridable); export
log_slow_events_threshold fallback (latent render bug).

Found while smoke-testing: pin --idn-library=idn (0.12's ICU default
segfaults without ICU data in the image); http became a private
service in 0.12 so 5280 needs http_interfaces to stay public; the
telnet console now depends on mod_admin_socket, whose socket moves to
/var/log/prosody.

Verified: prosodyctl check config clean; boots against Postgres with
empty error log and same port bindings as 0.11; healthcheck green;
telnet console and SQL storage round-trip; 0.11->0.12 schema upgrade
rehearsed on a 0.11-created database with data intact.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
2026-07-15 17:58:02 +02:00
Stefan-SangerandClaude Fable 5 2552a58872 refactor: convert prosody patches from full-file copies to unified diffs
Phase 0 of upgrade-plan.md. The 11 forked copies of 0.11.6 files in
patches/ are replaced by unified .patch files applied in the Dockerfile
builder stage with patch -p1 --fuzz=0 before make install, so upstream
drift fails the build instead of silently shipping stale forks. The
cp-over-installed-files block in the final stage is gone and /vnc/patches
no longer ships in the image. Stale patches.list replaced by a README
documenting each patch's intent.

Verified: installed prosody tree (269 files) is byte-identical to the
image built from the previous mechanism.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
2026-07-15 17:58:02 +02:00
Stefan-Sanger aef7c6a8d4 planning doc
Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
2026-07-15 17:58:02 +02:00
Stefan-Sanger 84e419705e Merge branch 'prepare-upgrade-hooks' into 'main'
fix: add dummy script to switch to new helm chart before prosody migration

See merge request uxf/vnctalk-prosody!2
2026-07-15 11:40:46 +00:00
Stefan-Sanger 54119c9ff1 fix: add dummy script to switch to new helm chart before prosody migration 2026-07-15 13:40:01 +02:00
Stefan-Sanger ae38d51dc6 fix: upgrade alpine base image
Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/1>
2026-06-08 10:04:47 +02:00
Stefan-Sanger 6f13736a77 fix: healthcheck
Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/1>
2026-06-08 09:33:01 +02:00
Stefan-Sanger abea16205a fix: basic rootless execution, optimize container image size
Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/1>
2026-06-08 09:18:18 +02:00
Stefan-Sanger 2e592f0ad6 fix: adjust directories
Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/1>
2026-06-08 07:37:48 +02:00
Stefan-Sanger d099c664d0 fix: config changes from claude report 2026-06-05 14:44:53 +02:00
Stefan-Sanger 8797ab1ee1 fix: config template typo 2026-06-05 12:34:49 +02:00
Stefan-Sanger d54d4076a3 fix: more debug output 2025-10-13 16:33:47 +02:00
Stefan-Sanger 8954d005d0 fix: debug REST send 2025-10-13 16:26:27 +02:00
Stefan-Sanger d9bc0e8cec fix: anon vhost 2025-06-18 07:46:13 +02:00
Stefan-Sanger 69530927ee fix: prepare cert automation 2025-06-18 07:43:18 +02:00
Stefan-Sanger 57457eb20e fix: ngx config 2025-06-16 12:46:13 +02:00
Stefan-Sanger 69c0d38a83 fix: typo 2025-06-16 12:34:41 +02:00
Stefan-Sanger bf0f574963 fix: add nginx to build 2025-06-16 12:14:10 +02:00
Stefan-Sanger ad0f05ee95 fix: add nginx 2025-06-16 12:00:21 +02:00
Stefan-Sanger 935ea283d0 fix: fcm with anonymous 2025-06-10 09:57:59 +02:00
Stefan-Sanger 31258dfcec fix: trivy execution 2025-03-17 09:53:32 +01:00
Stefan-Sanger 79c453112b fix: typo 2025-03-17 09:31:14 +01:00
Stefan-Sanger e4e25cf241 fix: add s2s keepalive for default jitsi 2025-03-17 09:23:35 +01:00
Stefan-Sanger 06f2766078 fix: cleanup debugging 2023-10-09 08:52:35 +02:00