Add end-to-end tests for TLS RPT report ingestion and WebSocket event handling

- Implemented tests for ingesting TLS RPT reports from emails and ensuring they are stored correctly in the database.
- Added tests to verify that the same report can be ingested multiple times without duplication.
- Created tests for backfilling reports that were previously delivered to the inbox.
- Developed WebSocket event handling tests to ensure events are correctly routed to subscribers based on mailbox ownership.
- Included tests for the mail API to validate session handling, mailbox isolation, and error mapping.
- Ensured that the API rejects unauthorized requests and handles malformed JSON gracefully.
This commit is contained in:
Lucas Rayan committed 2026-08-21 09:55:37 -03:00
1 parent 880dced9e4
commit f330c4324e
28 files changed
+2438 -6

No files matched your search

@@ -1,6 +1,7 @@
package entity
import (
"archive/zip"
"bytes"
"compress/gzip"
"encoding/xml"
@@ -55,10 +56,16 @@ type dmarcXmlReport struct {
} `xml:"record"`
}
// ParseDmarcXmlReport parses raw XML or gzipped XML DMARC aggregate report.
// ParseDmarcXmlReport parses a DMARC aggregate report: raw XML, gzipped XML,
// or XML inside a zip archive.
//
// Zip matters as much as gzip. Microsoft and Yahoo send .zip, and between them
// they account for a large share of the reports any domain receives; handling
// gzip alone meant those reports never parsed at all.
func ParseDmarcXmlReport(payload []byte) (*DmarcReport, error) {
data := payload
if isGzip(payload) {
switch {
case isGzip(payload):
gz, err := gzip.NewReader(bytes.NewReader(payload))
if err != nil {
return nil, fmt.Errorf("gzip reader: %w", err)
@@ -69,6 +76,12 @@ func ParseDmarcXmlReport(payload []byte) (*DmarcReport, error) {
return nil, fmt.Errorf("decompress gzip: %w", err)
}
data = decompressed
case isZip(payload):
decompressed, err := firstFileInZip(payload)
if err != nil {
return nil, err
}
data = decompressed
}
var parsed dmarcXmlReport
@@ -101,3 +114,41 @@ func ParseDmarcXmlReport(payload []byte) (*DmarcReport, error) {
func isGzip(payload []byte) bool {
return len(payload) >= 2 && payload[0] == 0x1f && payload[1] == 0x8b
}
// isZip reports whether the payload begins with a local file header. The
// empty-archive and spanned-archive signatures are deliberately not accepted:
// neither carries a report.
func isZip(payload []byte) bool {
return len(payload) >= 4 && payload[0] == 'P' && payload[1] == 'K' &&
payload[2] == 0x03 && payload[3] == 0x04
}
// firstFileInZip returns the contents of the first regular file in the
// archive. An aggregate report is one XML document per archive, so there is
// nothing to choose between; directories are skipped so an archive that
// carries one cannot be mistaken for an empty one.
func firstFileInZip(payload []byte) ([]byte, error) {
reader, err := zip.NewReader(bytes.NewReader(payload), int64(len(payload)))
if err != nil {
return nil, fmt.Errorf("zip reader: %w", err)
}
for _, file := range reader.File {
if file.FileInfo().IsDir() {
continue
}
handle, err := file.Open()
if err != nil {
return nil, fmt.Errorf("open %s in zip: %w", file.Name, err)
}
defer handle.Close()
// Bounded so a zip bomb cannot exhaust this process: an aggregate
// report is XML in the tens of kilobytes, and 64 MiB is far past any
// legitimate one.
decompressed, err := io.ReadAll(io.LimitReader(handle, 64<<20))
if err != nil {
return nil, fmt.Errorf("decompress %s in zip: %w", file.Name, err)
}
return decompressed, nil
}
return nil, fmt.Errorf("zip archive contains no report")
}