From 19e8b498d0fe1f4c9e4601e7349418a8f22e324c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 14 Jan 2026 16:45:26 +0000 Subject: [PATCH] Add source enrichment fields to forensic events matching aggregate reports Co-authored-by: seanthegeek <44679+seanthegeek@users.noreply.github.com> --- parsedmarc/google_secops.py | 8 +++++++- tests.py | 17 ++++++++++------- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/parsedmarc/google_secops.py b/parsedmarc/google_secops.py index aa3ec6b..8627743 100644 --- a/parsedmarc/google_secops.py +++ b/parsedmarc/google_secops.py @@ -465,6 +465,7 @@ class GoogleSecOpsClient: source_ip = forensic_report["source"]["ip_address"] source_country = forensic_report["source"].get("country") source_reverse_dns = forensic_report["source"].get("reverse_dns") + source_base_domain = forensic_report["source"].get("base_domain") source_name = forensic_report["source"].get("name") source_type = forensic_report["source"].get("type") @@ -509,7 +510,7 @@ class GoogleSecOpsClient: ], } - # Add optional fields to detection_fields + # Add optional fields to detection_fields (matching aggregate report field names) if source_name: event["security_result"][0]["detection_fields"].append( {"key": "dmarc.source_service_name", "value": source_name} @@ -522,6 +523,11 @@ class GoogleSecOpsClient: # Add optional context fields (low-value, not for dashboarding) additional_context = [] + if source_base_domain: + additional_context.append( + {"key": "source_base_domain", "value": source_base_domain} + ) + if forensic_report.get("feedback_type"): additional_context.append( {"key": "feedback_type", "value": forensic_report["feedback_type"]} diff --git a/tests.py b/tests.py index 4984c6e..e6e858b 100755 --- a/tests.py +++ b/tests.py @@ -162,7 +162,7 @@ class Test(unittest.TestCase): print() from parsedmarc.google_secops import GoogleSecOpsClient - client = GoogleSecOpsClient() + client = GoogleSecOpsClient(use_stdout=True) sample_path = "samples/aggregate/example.net!example.com!1529366400!1529452799.xml" print("Testing Google SecOps aggregate conversion for {0}: ".format(sample_path), end="") @@ -192,7 +192,7 @@ class Test(unittest.TestCase): from parsedmarc.google_secops import GoogleSecOpsClient # Test without payload - client = GoogleSecOpsClient(include_ruf_payload=False) + client = GoogleSecOpsClient(include_ruf_payload=False, use_stdout=True) sample_path = "samples/forensic/dmarc_ruf_report_linkedin.eml" print("Testing Google SecOps forensic conversion (no payload) for {0}: ".format(sample_path), end="") @@ -220,7 +220,8 @@ class Test(unittest.TestCase): # Test with payload client_with_payload = GoogleSecOpsClient( include_ruf_payload=True, - ruf_payload_max_bytes=100 + ruf_payload_max_bytes=100, + use_stdout=True ) print("Testing Google SecOps forensic conversion (with payload) for {0}: ".format(sample_path), end="") @@ -256,13 +257,14 @@ class Test(unittest.TestCase): print("Testing Google SecOps client configuration: ", end="") - # Test default configuration - client1 = GoogleSecOpsClient() + # Test stdout configuration + client1 = GoogleSecOpsClient(use_stdout=True) assert client1.include_ruf_payload is False assert client1.ruf_payload_max_bytes == 4096 assert client1.static_observer_vendor == "parsedmarc" assert client1.static_observer_name is None assert client1.static_environment is None + assert client1.use_stdout is True # Test custom configuration client2 = GoogleSecOpsClient( @@ -270,7 +272,8 @@ class Test(unittest.TestCase): ruf_payload_max_bytes=8192, static_observer_name="test-observer", static_observer_vendor="test-vendor", - static_environment="prod" + static_environment="prod", + use_stdout=True ) assert client2.include_ruf_payload is True assert client2.ruf_payload_max_bytes == 8192 @@ -285,7 +288,7 @@ class Test(unittest.TestCase): print() from parsedmarc.google_secops import GoogleSecOpsClient - client = GoogleSecOpsClient() + client = GoogleSecOpsClient(use_stdout=True) sample_path = "samples/smtp_tls/rfc8460.json" print("Testing Google SecOps SMTP TLS conversion for {0}: ".format(sample_path), end="")