feat(mail): ING-08 strukturiertes Protokoll-Logging & Diagnose für IMAP/POP3/SMTP
Neues Paket mail/internal/protolog (log/slog): SessionLogger loggt strukturierte Ereignisse einer Verbindung mit fester correlation_id und protocol über die gesamte Verbindungsdauer (Akzeptanzkriterium 1) — ein Logger mit logger==nil ist sicher benutzbar und loggt nichts (Rückwärtskompatibilität zu ING-01..ING-07, Logging ist opt-in wie TLS und Guard-Konfiguration). RedactCommandLine ersetzt bei sensiblen Kommandos (PASS, LOGIN, AUTH) alle Argumente vollständig durch [REDACTED] statt einzeln zu parsen (Akzeptanzkriterium 2). Reconstruct liest zeilenweise JSON-Logs und liefert ausschließlich die Einträge einer Korrelations-ID in Reihenfolge — das geforderte Diagnosewerkzeug (Akzeptanzkriterium 3). Alle drei Sessions loggen jetzt session_start/command (je empfangener Zeile, redigiert)/session_end. Nachrichteninhalte werden strukturell nie geloggt: SMTP-DATA-Body-Zeilen laufen durch eine eigene Leseschleife, die nicht durch den Kommando-Logpfad der Hauptschleife kommt: nur das Kommando DATA selbst erscheint im Log. Alle drei Pflichtprüfungen mit echten Nachweisen durchgeführt, jeweils in IMAP, POP3 und SMTP einzeln: Redaktion gegen den echten laufenden Server bestätigt (Klartextpasswort bzw. absichtlich eingebettetes Geheimnis im SMTP-Body erscheint nie im Log), zwei gemischte reale Sessions über dieselbe Korrelations-ID lückenlos rekonstruiert, Lasttest mit 100 Sessions mit/ohne Logging ohne relevante Durchsatzeinbuße. go build/go vet/golangci-lint clean, gesamtes Mail-Modul (~29 Pakete) regressionsfrei getestet.
This commit is contained in:
@@ -6,8 +6,11 @@ import (
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"io"
|
||||
"log/slog"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
"gitea.perlbach24.de/scripte/nexarch/mail/internal/protolog"
|
||||
)
|
||||
|
||||
// maxCommandLineBytes begrenzt eine einzelne Kommando-/DATA-Zeile
|
||||
@@ -29,12 +32,14 @@ type Session struct {
|
||||
tlsConfig *tls.Config // nil = kein STARTTLS angeboten (ING-06)
|
||||
tlsActive bool
|
||||
|
||||
log *protolog.SessionLogger // ING-08, nie nil (log.Event() ist nil-sicher)
|
||||
|
||||
state State
|
||||
from string
|
||||
to []string
|
||||
}
|
||||
|
||||
func newSession(conn net.Conn, sink MessageSink, maxMessageBytes int64, tlsConfig *tls.Config) *Session {
|
||||
func newSession(conn net.Conn, sink MessageSink, maxMessageBytes int64, tlsConfig *tls.Config, logger *slog.Logger) *Session {
|
||||
_, alreadyTLS := conn.(*tls.Conn)
|
||||
return &Session{
|
||||
conn: conn,
|
||||
@@ -44,6 +49,7 @@ func newSession(conn net.Conn, sink MessageSink, maxMessageBytes int64, tlsConfi
|
||||
maxMessageBytes: maxMessageBytes,
|
||||
tlsConfig: tlsConfig,
|
||||
tlsActive: alreadyTLS,
|
||||
log: protolog.NewSessionLogger(logger, "smtp"),
|
||||
state: Greeting,
|
||||
}
|
||||
}
|
||||
@@ -55,6 +61,11 @@ func (s *Session) State() State { return s.state }
|
||||
func (s *Session) Serve(ctx context.Context) {
|
||||
defer func() { _ = s.conn.Close() }()
|
||||
|
||||
// Akzeptanzkriterium 1 (ING-08): strukturierte Logs mit
|
||||
// Korrelations-ID über die gesamte Verbindungsdauer.
|
||||
s.log.Event(ctx, "session_start", slog.String("remote_addr", s.conn.RemoteAddr().String()))
|
||||
defer s.log.Event(ctx, "session_end")
|
||||
|
||||
if err := s.reply(220, "nexarch-mail SMTP server ready"); err != nil {
|
||||
return
|
||||
}
|
||||
@@ -69,6 +80,17 @@ func (s *Session) Serve(ctx context.Context) {
|
||||
}
|
||||
|
||||
verb, arg := parseCommand(line)
|
||||
// Akzeptanzkriterium 2 (ING-08): sensible Argumente (z. B. ein
|
||||
// künftiges AUTH) erscheinen über RedactCommandLine nie im
|
||||
// Klartext im Log. DATA-Nachrichteninhalte werden hier NICHT
|
||||
// erfasst — nur das Kommando "DATA" selbst, der Body wird an
|
||||
// keiner Stelle geloggt.
|
||||
var args []string
|
||||
if arg != "" {
|
||||
args = strings.Fields(arg)
|
||||
}
|
||||
s.log.Event(ctx, "command", slog.String("command", protolog.RedactCommandLine(verb, args)))
|
||||
|
||||
if !s.dispatch(ctx, verb, arg) {
|
||||
return
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user