logtail: deliveryRe anchored at the head of the line (audit M12)
The pattern that writes a row's status matched anywhere in a line: a port-25 reject line ending helo=<ID: to=<victim@...>, status=sent> parsed as (ID, victim, sent). parseDelivery now takes the stamp off with SplitTimestamp and matches `^host program[pid]: <id>: to=<...>, ... status=`, as queueLineRe and the inbound patterns do. Tests: the probed HELO line, the same text in a quoted sender on a qmgr line, the text after an smtpd line's queue id - none parse; a syslog-stamped line as Postfix 3.7 writes it parses. The existing cases unchanged. CHANGELOG [Unreleased], audit plan line ticked, roadmap 11/61. Evidence: go test ./internal/logtail ok but for TestFollowTailsAndRotates (Windows); the server run of the stage follows before the push. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -88,17 +88,25 @@ type RetentionDays func() int
|
||||
// The "<queue-id>: to=<addr>, …, status=<word>" shape is specific to the
|
||||
// delivery agents; qmgr/smtpd/cleanup lines do not match.
|
||||
//
|
||||
// It is matched at the head of the line - the host name, "program[pid]:",
|
||||
// then the queue id - after SplitTimestamp has taken the stamp off, like
|
||||
// queueLineRe and the inbound patterns. Anywhere else the text is a
|
||||
// stranger's: a port-25 reject line ends with the client's HELO name, which
|
||||
// once parsed as a delivery result when it read "<id>: to=<…>, status=sent"
|
||||
// (audit 2026-10-12, M12).
|
||||
//
|
||||
// The run before status= is lazy on purpose. Postfix appends the remote
|
||||
// server's reply verbatim, so a greedy match would take the *last* status= on
|
||||
// the line — and that one can come from the reply text, which the far end
|
||||
// controls. A bounce whose reply quoted "status=sent" would then be filed as a
|
||||
// success. The real field is always the first one after to=<…>.
|
||||
var deliveryRe = regexp.MustCompile(`\b([0-9A-Za-z]+): to=<([^>]*)>,.*?\bstatus=(\w+)`)
|
||||
var deliveryRe = regexp.MustCompile(`^\S+ [^\s\[]+\[\d+\]: ([0-9A-Za-z]+): to=<([^>]*)>,.*?\bstatus=(\w+)`)
|
||||
|
||||
// parseDelivery extracts (queue-id, recipient, status) from a mail.log line.
|
||||
// ok is false for lines that are not recognised delivery results.
|
||||
func parseDelivery(line string) (queueID, recipient, status string, ok bool) {
|
||||
m := deliveryRe.FindStringSubmatch(line)
|
||||
_, rest := SplitTimestamp(line)
|
||||
m := deliveryRe.FindStringSubmatch(rest)
|
||||
if m == nil {
|
||||
return "", "", "", false
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user