Iterates on the docker-based repro infrastructure while diagnosing the
portal@unsandbox.com 'peer closed after 0/4 bytes' failure:
- _write_ssl_config_portal_match() emits an ssl_dist.config with the
exact options portal runs: permissive verify_fun (accepts bad_cert),
versions [tlsv1.3, tlsv1.2], secure_renegotiate, server_name_indication
disabled. Same shape as /opt/unsandbox/certs/inet_tls.conf.
- Elixir docker peer now boots with --name (long FQDN, like prod)
instead of --sname (short). Production portal is portal@unsandbox.com
so the dist driver's routing path is different from short-name peers.
- Elixir GenTarget now logs init + handle_call + handle_info. Fixture
redirects container stdout to a file; test prints it on
pass-or-fail so we can see whether the peer received our gen_call.
- elixir image bumped to 1.16-otp-25 (portal runs OTP 25.3.2.5 / erts
13.2.2.5, NOT OTP 26 — discovered via the portal release's bundled
erts version).
Despite matching every dimension I can find (OTP version, TLS dist
config, Elixir GenServer wrapping, long node names), the test still
passes locally — so the production failure is something specific to
the live portal beam state, not a general protocol or version issue.
Reproduces the production failure locally so we can iterate in seconds
instead of waiting on deploy cycles across 3 repos and PyPI.
Existing test_node.py / test_tls.py use the system Erlang which is
OTP 24 on most dev boxes (Ubuntu 22.04 default) — silently masks
flag-negotiation and protocol bugs that only surface against OTP 25+.
Adds four docker-backed tests:
- plain dist + hand-coded receive (works on all OTP versions)
- TLS dist + hand-coded receive (works on all OTP versions)
- TLS dist + Elixir GenServer (FAILS on OTP 25, passes on 26)
The last one is the minimum repro of the portal@unsandbox.com failure
mode. Once a fix lands, that test goes green and we know the
production smoke test will too.
Uses --network host to share the host's epmd (Linux-only). Docker mounts
from $HOME/.erldistpy-test/ because snap-confined docker can't see /tmp.
Tests skip cleanly when docker isn't installed.