Files
bongo/contrib/testing

Local mail protocol fixtures

These fixtures are intentionally bound to loopback and use non-standard ports. They are development tools, not production configuration.

Cyrus IMAP, POP3, and LMTP

Install net-mail/cyrus-imapd, then start the disposable fixture as root:

sudo ./contrib/testing/cyrus-fixture.py start

It creates no files outside /tmp/bongo-cyrus-fixture and listens on:

  • IMAP: 127.0.0.1:18143
  • POP3: 127.0.0.1:18110
  • LMTP: 127.0.0.1:18024

The source mailboxes form a multi-account-per-user matrix:

Bongo owner Cyrus source account Protocol Bongo destination
test1 test1-pop@cyrus.bongo.test POP3 INBOX
test1 test1-imap@cyrus.bongo.test IMAP Cyrus IMAP
test2 test2-pop@cyrus.bongo.test POP3 INBOX
test2 test2-imap@cyrus.bongo.test IMAP Cyrus IMAP

All source accounts use the test-only password BongoCollector-Test-2026. Insert a complete RFC 5322 message through Cyrus' real LMTP delivery path:

sudo ./contrib/testing/cyrus-fixture.py inject message.eml

Seed three different messages in each source mailbox and exercise Bongo's real Collector POP3 and IMAP transport implementation:

./contrib/testing/cyrus-fixture.py verify-collector \
  --probe ./build/src/agents/collector/collector-remote-transport-probe \
  --count 3

The probe lists and fetches every message, checks its fixture marker, deletes it through the selected protocol, and verifies that every Cyrus source mailbox is empty. A live end-to-end run creates all four Bongo external-account records. This proves that accounts, remote UID/UIDL values, retry state and deletion state remain scoped by account ID even when one Bongo user owns multiple sources. All four use after_import, so Cyrus deletion happens only after the Bongo Queue has durably accepted and committed the complete message. From that point the normal scanner, rules, quota, and Store delivery pipeline owns it.

The fixture can also seed deterministic scanner and quota cases. All ports remain loopback-only and the flood is deliberately bounded:

sudo ./contrib/testing/cyrus-fixture.py seed --profile gtube --count 1
sudo ./contrib/testing/cyrus-fixture.py seed --profile eicar --count 1
sudo ./contrib/testing/cyrus-fixture.py seed --profile flood --count 32 \
  --message-size 131072
sudo ./contrib/testing/cyrus-fixture.py seed-suite

gtube contains SpamAssassin's standard GTUBE string. eicar creates the harmless standard EICAR attachment at runtime; the complete signature is kept out of the Git checkout to avoid host antivirus false alarms. seed-suite places three normal messages, one GTUBE message, one EICAR message, and 32 128-KiB flood messages in every source mailbox (148 messages total). Set a small quota on disposable Bongo users before collection, then restore it after the test. The test passes only when clean messages are imported, scanner policy is applied, quota cannot be exceeded, and a message rejected before a durable import remains retrievable from Cyrus.

The same LMTP listener is the forwarding target for the exact transport-domain mapping below. This accepts *@cyrus.bongo.test without making the test domain a local Bongo domain:

"lmtp_transports": ["cyrus.bongo.test=127.0.0.1:18024"]

Cyrus lmtpd is pre-authorized only on this loopback-only fixture listener. That matches a trusted local MTA-to-store LMTP hop and must not be copied to a network-exposed Cyrus listener.

The generated short-lived test CA at /tmp/bongo-cyrus-fixture/tls/ca.crt is the fixture trust anchor. Set BONGO_COLLECTOR_CAINFO to that path for the Collector process during this test; normal installations continue to use the operating-system trust store. The packaged bongo.service uses PrivateTmp=true, so a live systemd test must make the fixture visible inside that service namespace. A runtime-only drop-in can bind precisely this fixture read-only:

[Service]
BindReadOnlyPaths=/tmp/bongo-cyrus-fixture

Install it with systemctl edit --runtime bongo.service, restart Bongo, and set the Collector ca_file to the path above. Do not weaken certificate or host-name verification for the test.

After a live collection cycle, show the source-mailbox counts with:

./contrib/testing/cyrus-fixture.py mailbox-status

Stop or remove all fixture state with:

sudo ./contrib/testing/cyrus-fixture.py stop
sudo ./contrib/testing/cyrus-fixture.py reset

Outbound SMTP capture

Use net-mail/xeams-devnullsmtp-bin from the Bongo Gentoo overlay:

xeams-devnullsmtp -p 2526 -d bongo.test -s /tmp/bongo-devnull-mail

Configure 127.0.0.1:2526 as Bongo's relay host before testing any non-local recipient. Xeams DevNullSMTP has no listen-address option, so isolate it with a firewall or network namespace; do not expose it on a production network.

HAProxy and PROXY v2

haproxy-bongo-test.cfg exposes loopback-only high ports and forwards every connection to the corresponding normal Bongo listener with a PROXY v2 header. Before starting it, temporarily enable proxy_protocol_enabled and set proxy_protocol_networks to ["127.0.0.1/32"] in the smtp, imap, pop3, and sieve documents. Never trust an unbounded network for PROXY headers.

Validate and run the fixture in the foreground:

haproxy -c -f contrib/testing/haproxy-bongo-test.cfg
haproxy -db -f contrib/testing/haproxy-bongo-test.cfg

The test listeners are SMTP 11025, submission 11587, submissions 11465, IMAP 11143, IMAPS 11993, POP3 11110, POP3S 11995, and ManageSieve 14190. Exercise real protocol greetings, capabilities, authentication, and TLS handshakes through these ports, then restore the original Bongo documents.