Make backup report hostname configurable

This commit is contained in:
admin committed 2026-09-12 18:53:01 +02:00
1 parent 99da6460d2
commit 64eab1d3c2
7 files changed
+121 -7

No files matched your search

+36
View File
@@ -11,6 +11,7 @@ import os
from pathlib import Path
import shutil
import signal
import socket
import subprocess
import tarfile
import tempfile
@@ -584,6 +585,7 @@ if '--list-only' not in sys.argv and '--exclude=/*' not in sys.argv:
def test_automatic_package_upgrade_and_combined_rollback(self):
self.enable_report()
with self.config.open('a') as f: f.write('MAIL_HOSTNAME="gemini.jr-it-services.de"\n')
canonical=self.configure_upgrade()
original=canonical.read_bytes()
package=self.build_package()
@@ -593,6 +595,9 @@ if '--list-only' not in sys.argv and '--exclude=/*' not in sys.argv:
self.assertIn('SUCCESS',(state/'result.txt').read_text())
message,body=self.read_report()
self.assertEqual(str(message['From']),'app-backup@example.invalid')
self.assertIn(' SUCCESS gemini.jr-it-services.de ',str(message['Subject']))
self.assertIn('Host: gemini.jr-it-services.de',body.splitlines())
self.assertIn('MAIL_HOSTNAME="gemini.jr-it-services.de"',canonical.read_text())
self.assertIn('OK (Inhalt und Abschlussmarker',body)
self.assertEqual(Path('/usr/local/lib/app-backup/report.py').read_bytes(),(REPO/'lib/report.py').read_bytes())
self.assertTrue((state/'verified-backup-run').is_file())
@@ -987,6 +992,8 @@ REPORT_SECRET='config-content-must-not-enter-the-mail'
run=self.backup()
message,body=self.read_report()
self.assertIn('[Backup-Test] SUCCESS',str(message['Subject']))
self.assertIn(f' SUCCESS {socket.getfqdn()} ',str(message['Subject']))
self.assertIn(f'Host: {socket.getfqdn()}',body.splitlines())
self.assertEqual(str(message['From']),'app-backup@example.invalid')
self.assertIn('backup@example.invalid',str(message['To']))
for value in ['Status: SUCCESS','Exit code: 0','Dauer:', 'db staged:',
@@ -1000,12 +1007,41 @@ REPORT_SECRET='config-content-must-not-enter-the-mail'
self.assertEqual(saved.read_bytes(),(self.base/'mail.eml').read_bytes())
self.assertEqual(saved.stat().st_mode & 0o777,0o600)
def test_report_hostname_override_preserves_default_sender(self):
self.enable_report()
with self.config.open('a') as f:
f.write('MAIL_HOSTNAME="gemini.jr-it-services.de"\nMAIL_FROM=""\n')
run=self.backup()
message,body=self.read_report()
self.assertEqual(str(message['Subject']),f'[Backup-Test] SUCCESS gemini.jr-it-services.de {run.name}')
self.assertIn('Host: gemini.jr-it-services.de',body.splitlines())
self.assertEqual(str(message['From']),f'app-backup@{socket.getfqdn()}')
def test_report_empty_hostname_uses_system_fqdn(self):
self.enable_report()
with self.config.open('a') as f: f.write('MAIL_HOSTNAME=""\n')
self.backup()
message,body=self.read_report()
self.assertIn(f' SUCCESS {socket.getfqdn()} ',str(message['Subject']))
self.assertIn(f'Host: {socket.getfqdn()}',body.splitlines())
def test_report_hostname_header_injection_is_rejected(self):
self.enable_report()
with self.config.open('a') as f:
f.write("MAIL_HOSTNAME=$'gemini\\nBcc: attacker@example.invalid'\n")
result=self.run_script('app-backup.sh')
self.assertIn('mail report failed (ValueError)',result.stdout)
self.assertFalse((self.base/'mail.eml').exists())
def test_report_failure_names_phase_and_has_final_error(self):
self.enable_report()
with self.config.open('a') as f: f.write('MAIL_HOSTNAME="gemini.jr-it-services.de"\n')
result=self.run_script('app-backup.sh',ok=False,TEST_FAIL_TOOL='mariadb-dump')
message,body=self.read_report()
self.assertEqual(result.returncode,42)
self.assertIn('[Backup-Test] FAIL',str(message['Subject']))
self.assertIn(' FAIL gemini.jr-it-services.de ',str(message['Subject']))
self.assertIn('Host: gemini.jr-it-services.de',body.splitlines())
self.assertIn('Exit code: 42',body)
self.assertIn('Letzte Phase: DB-Dump:',body)
self.assertIn('FAILED (exit 42)',body)