mirror of
https://github.com/domainaware/parsedmarc.git
synced 2026-09-06 05:57:58 +00:00
* Make the output and mailbox integrations optional extras (#883) Breaking change for the next major release: pip install parsedmarc now installs the parsing core plus a working core CLI (file, IMAP, Maildir, and mbox input; CSV/JSON, Splunk HEC, webhook, and syslog output). Everything else moves behind an extra: elastic, opensearch, kafka, s3, gelf, loganalytics, msgraph, and gmail, joining the existing postgresql extra, with an umbrella [all] that deliberately excludes postgresql (psycopg's binary wheels do not exist on every platform, so parsedmarc[all] must never fail to install there). cli.py imports the six SDK-dependent output modules behind the #884 TYPE_CHECKING/try-except guard; a configured section whose extra is missing fails fast with a ConfigurationError naming the section and the exact pip install command — including the msgraph and gmail_api mailbox sections (detected via parsedmarc.mail's placeholder classes) and postgresql (checked before the constructor so the startup retry loop does not retry a missing dependency for a minute). The Azure/kiota Graph error types fall back to never-raised sentinel classes. The Docker image installs [all,postgresql], so container users see no change. CI lint installs [build,all,postgresql]; the unit-test job installs [build,all], deliberately without postgresql so test_postgres.py's absent-psycopg arm stays exercised. The never-imported dateparser dependency is dropped in favor of declaring python-dateutil, which utils.py actually imports; pytz moves to the build extra for the one test that uses it. Verified live: a no-extras wheel install imports, parses samples, and reports the install hint for each gated section; a [all] install restores every integration; the Docker image builds with every SDK importable. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Patch psycopg presence in the PostgreSQL CLI wiring tests CI's unit-test job deliberately installs [build,all] without the postgresql extra, so parsedmarc.cli.postgres.psycopg is None there and the new missing-extra presence check correctly made _main exit 1 before the wiring under test ran. The tests simulate the SDK being available (PostgreSQLClient is mocked at the SDK boundary), so the module-level psycopg handle is now patched present in setUp. Verified against a simulated psycopg-absent environment as well as the local full install. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Address Copilot review: narrow guards to ModuleNotFoundError, fix docs - The optional-integration and Graph error-type import guards now catch ModuleNotFoundError instead of ImportError, so only a genuinely absent package reads as a missing extra; a broken-but-present SDK fails loudly with its real error instead of masquerading as one. The test blocker raises ModuleNotFoundError accordingly — the exact exception a missing package produces. - _missing_extra_hint docstring no longer calls every gated integration an output module (it also serves the msgraph/gmail_api mailbox sections). - Fix the pre-existing passsword typo in usage.md's kafka section; the INI key the code reads is password (cli.py _parse_config). Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Quote extras specs in copy-paste install commands From Copilot's second review round: zsh treats an unquoted .[build,all] as a glob and fails with 'no matches found', so the commands shown in AGENTS.md, CONTRIBUTING.md, dashboards/README.md, and the bootstrap script's comment are now quoted. The CI workflows keep the unquoted form: they run under bash, which passes unmatched globs through literally. The suggestion to change the 'Choosing what to install' heading level was rejected — it is a subsection of 'Installing parsedmarc', matching the file's existing hierarchy. Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Fix upgrade command in the changelog * Documentation review: accuracy, spelling, grammar, and clarity pass A full prose review of docs/source, README, CONTRIBUTING, and the dashboards README, with every accuracy claim verified against the code before changing it. Highlights: - usage.md: documented six missing [general] options (the CSV/JSON filename options, prettify_json, normalize_timespan_threshold_hours), the required kafka smtp_tls_topic, [imap] timeout/max_retries, and the postgresql env-var prefix; corrected the maildir_path default (None, not INBOX — cli.py Namespace defaults), the mailbox check_timeout option name, the systemd restart interval (RestartSec is 5m), and merged the duplicate silent entry; quoted every copy-paste extras spec for zsh safety. - elasticsearch.md: fixed an invalid openssl command (rsa:4096 -nodes), the dashboards filename (opensearch_dashboards.ndjson, matching the file the link serves), and assorted grammar. - davmail.md: the service-enable command now enables davmail.service (was parsedmarc.service — a copy-paste error that left DavMail unenabled), plus a view typo and DavMail capitalization. - output.md: the example schema reference is RFC 7489 Appendix C (7480 is RDAP). kibana.md: SPF relies on the SMTP envelope, not session headers (RFC 7208). dmarc.md: DKM -> DKIM. - README: the intro now also names the OpenSearch/Grafana stack, matching the feature list. CONTRIBUTING: pre-PR checks now include ruff format --check and pyright, matching CI's lint job. - dashboards/README: the service table and seed description now include the PostgreSQL backend the compose stack runs. Sample data blocks, the CLI-help mirror block, and released CHANGELOG entries were deliberately left untouched. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Docstring review: accuracy, spelling, grammar, and clarity pass Every docstring in parsedmarc/, parsedmarc/mail/, the maps maintainer scripts, and the test suite reviewed with each claim verified against the code it documents. Text-only — no behavior changes. Highlights: - Copy-paste errors corrected: parsed_smtp_tls_reports_to_csv and splunk/loganalytics save functions described aggregate or failure reports they do not handle; LogAnalyticsException claimed to be an Elasticsearch error. - Docstring/behavior mismatches: parse_report_email's report_type enumeration omitted smtp_tls; parse_failure_report typed msg_date as str (it is datetime); strip_attachment_payloads claimed payloads are replaced with None (the key is deleted); kafkaclient's failure and SMTP TLS savers claimed per-record slicing while sending the whole list in one message (docstrings now describe reality — whether slicing was intended is flagged for follow-up); the postgres savers claimed to take parse_report_file's return value but receive the inner report dict; elastic/opensearch save functions' Raises listed only AlreadySaved. - None-as-semantic-state documented where missing (get_base_domain, get_ip_address_country), enumeration completeness fixed (get_ip_address_info's 9 result keys, maps script outputs, TSV columns), and the stale 44-industry-types count corrected to the 46 the authoritative README list defines. - Test docstrings aligned with what the tests actually assert, including two that overstated coverage of the elastic/opensearch address-list tests. - Two argparse help strings fixed: file_path now names SMTP TLS report files alongside aggregate and failure, mirrored into usage.md's CLI-help block; --offline's doubled spaces removed (rendered help unchanged). - elasticsearch.md's security claim corrected against Elastic's docs: security is enabled and auto-configured on first startup since 8.0 (not "8.7 secure mode"), so the settings are verified, not hand-written. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
143 lines
7.0 KiB
Markdown
143 lines
7.0 KiB
Markdown
|
|
# Using the Kibana dashboards
|
|
|
|
The Kibana DMARC dashboards are a human-friendly way to understand the
|
|
results from incoming DMARC reports.
|
|
|
|
There is no separate Kibana export — Kibana 8.x's saved-object migration
|
|
handlers accept the OpenSearch Dashboards format directly, so Kibana
|
|
users import the bundled
|
|
[`dashboards/opensearch/opensearch_dashboards.ndjson`](https://raw.githubusercontent.com/domainaware/parsedmarc/master/dashboards/opensearch/opensearch_dashboards.ndjson)
|
|
in *Stack Management → Saved Objects → Import*. A CI check imports the
|
|
same file into a Kibana 8.x container on every change so this stays
|
|
compatible.
|
|
|
|
:::{note}
|
|
The default dashboard is DMARC aggregate reports. To switch between
|
|
dashboards, click on the Dashboard link on the left side menu of Kibana.
|
|
:::
|
|
|
|
## DMARC aggregate reports
|
|
|
|
As the name suggests, this dashboard is the best place to start
|
|
reviewing your aggregate DMARC data.
|
|
|
|
Across the top of the dashboard, three pie charts display the percentage of
|
|
alignment pass/fail for SPF, DKIM, and DMARC. Clicking on any chart segment
|
|
will filter for that value.
|
|
|
|
:::{note}
|
|
Messages should not be considered malicious just because they failed to pass
|
|
DMARC, especially if you have just started collecting data. It may be a
|
|
legitimate service that needs SPF and DKIM configured correctly.
|
|
:::
|
|
|
|
Start by filtering the results to only show failed DKIM alignment. While DMARC
|
|
passes if a message passes SPF or DKIM alignment, only DKIM alignment remains
|
|
valid when a message is forwarded without changing the from address, which is
|
|
often caused by a mailbox forwarding rule. This is because DKIM signatures are
|
|
part of the message headers, whereas SPF relies on the SMTP envelope.
|
|
|
|
Underneath the pie charts, you can see graphs of DMARC compliance and message
|
|
disposition over time.
|
|
|
|
Under the graphs you will find the most useful data tables on the dashboard. On
|
|
the left, there is a list of organizations that are sending you DMARC reports.
|
|
In the center, there is a list of sending servers grouped by the base domain
|
|
in their reverse DNS. On the right, there is the "Message volume and DMARC
|
|
compliance by from domain" table, which lists email from domains with their
|
|
message volume and a percentage of those messages that passed DMARC.
|
|
|
|
By hovering your mouse over a data table value and using the magnifying glass
|
|
icons, you can filter on or filter out different values. Start by looking at
|
|
the Message Sources by Reverse DNS table. Find a sender that you recognize,
|
|
such as an email marketing service, hover over it, and click on the plus (+)
|
|
magnifying glass icon, to add a filter that only shows results for that sender.
|
|
Now, look at the Message volume and DMARC compliance by from domain table to
|
|
the right. That shows you the domains that a sender is sending as, and what
|
|
share of that traffic is passing DMARC, which might tell you which
|
|
brand/business is using a particular service. With that information, you can
|
|
contact them and have them set up DKIM.
|
|
|
|
:::{note}
|
|
The "Message volume and DMARC compliance by from domain" table is a TSVB
|
|
visualization, used because per-domain compliance percentages require a
|
|
Filter Ratio metric that agg-based data tables can't compute. It renders
|
|
correctly on Kibana 8.x as imported, but *editing* it requires first enabling
|
|
the `metrics:allowStringIndices` advanced setting, since it references the
|
|
`dmarc_aggregate*` index as a string pattern, which Elastic has deprecated.
|
|
:::
|
|
|
|
:::{note}
|
|
If you have a lot of B2C customers, you may see a high volume of emails as
|
|
your domains coming from consumer email services, such as Google/Gmail and
|
|
Yahoo! This occurs when customers have mailbox rules in place that forward
|
|
emails from an old account to a new account, which is why DKIM
|
|
authentication is so important, as mentioned earlier. Similar patterns may
|
|
be observed with businesses who send from reverse DNS addresses of
|
|
parent, subsidiary, and outdated brands.
|
|
:::
|
|
|
|
Further down the dashboard, you can filter by source country or source IP
|
|
address.
|
|
|
|
Tables showing SPF and DKIM alignment details are located under the IP address
|
|
table. Each row of the DKIM details table is one real DKIM signature, shown
|
|
as a combined `selector / domain / result` value; the SPF details table
|
|
shows `scope / domain / result` the same way. Combining the values into one
|
|
column keeps each signature's selector, domain, and result paired together,
|
|
rather than aggregating them as separate columns. Because a message that
|
|
carries multiple DKIM signatures appears once per signature, summing the
|
|
messages column across rows can exceed the total number of messages.
|
|
|
|
The "Auth result filters" panel above the details tables
|
|
provides dropdowns for the individual auth-result components — DKIM
|
|
selector, DKIM domain, DKIM result, SPF scope, SPF domain, and SPF
|
|
result — and filters the whole dashboard by them. Because components from
|
|
different signatures of the same message are indexed together, combining
|
|
two of these component filters matches documents where any signature
|
|
satisfies each condition individually, not necessarily the same signature;
|
|
the combined `selector / domain / result` (`scope / domain / result`)
|
|
column remains the per-signature source of truth.
|
|
|
|
:::{note}
|
|
The alignment tables (SPF details, DKIM details) and the per-IP source
|
|
table live on the same dashboard, further down. To view failures only,
|
|
use the pie chart at the top of the page as a filter.
|
|
:::
|
|
|
|
Any other filters work the same way. You can also add your own custom temporary
|
|
filters by clicking on Add Filter at the upper right of the page.
|
|
|
|
## DMARC failure reports
|
|
|
|
The DMARC failure reports dashboard (formerly DMARC Forensic Samples) contains
|
|
information on DMARC failure reports (also known as forensic or ruf reports).
|
|
These reports contain samples of emails that have failed to pass DMARC.
|
|
|
|
:::{note}
|
|
Most recipients do not send failure/ruf reports at all to avoid
|
|
privacy leaks. Some recipients (notably Chinese webmail services) will only
|
|
supply the headers of sample emails. Very few provide the entire email.
|
|
:::
|
|
|
|
## SMTP TLS reporting
|
|
|
|
The SMTP TLS reporting dashboard surfaces aggregate counts of TLS-RPT
|
|
reporting organizations, the policy domains they report on, and the
|
|
specific failure types — certificate expiry, STARTTLS not supported,
|
|
STS policy fetch errors, validation failures, and similar — together with
|
|
the sending and receiving MTA addresses involved.
|
|
|
|
Like the DKIM and SPF details tables above, the "SMTP TLS domains" and
|
|
"SMTP TLS failure details" tables show one row per policy and one row per
|
|
failure detail, respectively, using combined `policy (domain / type)` and
|
|
`failure detail (domain / type / result / sending mta / receiving ip / mx)`
|
|
columns so that each policy's or failure detail's fields stay paired
|
|
together, rather than aggregating them as separate columns. The
|
|
`successful_sessions` and `failed_sessions` columns are summed per report
|
|
document, though, not per policy: when a single report carries multiple
|
|
policies, a row's session sums include the sibling policies from that
|
|
report as well as its own. Fully attributing session counts to a single
|
|
policy would require restructuring the stored documents.
|