75.4 Ловушка почты: catch-all только для адресов без своего ящика, файл с паролями

- MailRouter: существующий ящик получает свою почту, всё остальное (и чужие домены) —
  в ящик MAIL_CATCH_ALL; раньше ловушка забирала и письма между ящиками стенда
- DataInitializer: ящик-ловушка создаётся при старте; случайные пароли — в
  MAIL_PASSWORDS_FILE (права 600, в образе /app/data/initial-passwords.txt)
- docker-compose.jambotron.yml: MAIL_CATCH_ALL=trap@mail.test по умолчанию
- README: ловушка, файл паролей, что нужно для staging Jambotron (TCP-проброс SMTP)
- тесты: MailRouterTest, DataInitializerTest (33 всего)

α
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-11-05 17:43:49 +01:00
parent db0249eb74
commit 12c2223c15
8 changed files with 192 additions and 27 deletions
@@ -0,0 +1,26 @@
package com.mailserver.config;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.PosixFilePermissions;
import static org.assertj.core.api.Assertions.assertThat;
class DataInitializerTest {
@Test
void generatedPasswordsAreAppendedToAFileOnlyTheOwnerReads(@TempDir Path dir) throws Exception {
Path file = dir.resolve("data/initial-passwords.txt");
DataInitializer.appendPassword(file, "admin@mail.test", "secret-1");
DataInitializer.appendPassword(file, "trap@mail.test", "secret-2");
assertThat(Files.readAllLines(file)).hasSize(2);
assertThat(Files.readAllLines(file).get(0)).endsWith(" admin@mail.test secret-1");
assertThat(Files.readAllLines(file).get(1)).endsWith(" trap@mail.test secret-2");
assertThat(PosixFilePermissions.toString(Files.getPosixFilePermissions(file))).isEqualTo("rw-------");
}
}