Skip to content

PYTHON-6080 Introduce Custom Callback logic in Configurable DNS - #3051

Open
sleepyStick wants to merge 44 commits into
mongodb:mainfrom
sleepyStick:PYTHON-5814
Open

sleepyStick wants to merge 44 commits into
mongodb:mainfrom
sleepyStick:PYTHON-5814

Conversation

@sleepyStick

@sleepyStick sleepyStick commented Sep 11, 2026 •

Copy link
Copy Markdown
Contributor

PYTHON-6080

Changes in this PR

  • add srvHostValidator
  • some modifications to srvAllowedHostsSuffix (allowing things like localhost to be considered valid)
  • found a bug in SRV polling where the topology wouldn't change (new hosts wouldn't be added and hosts no longer in DNS wouldn't be removed) if one returned host was invalid

Test Plan

  • prose tests
  • added a new test for the srv bug too

Checklist

Checklist for Author

  • Did you update the changelog (if necessary)?
  • Is there test coverage?
  • Is any followup work tracked in a JIRA ticket? If so, add link(s).

Checklist for Reviewer

  • Does the title of the PR reference a JIRA Ticket?
  • Do you fully understand the implementation? (Would you be comfortable explaining how this code works to someone else?)
  • Is all relevant documentation (README or docstring) updated?

sleepyStick and others added 30 commits June 11, 2026 13:53
…was only here for the initial delivery of the project, removing now
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@codecov

codecov Bot commented Sep 11, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 85.82677% with 18 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
pymongo/synchronous/srv_resolver.py 78.00% 6 Missing and 5 partials ⚠️
pymongo/asynchronous/srv_resolver.py 90.00% 3 Missing and 2 partials ⚠️
pymongo/_telemetry.py 33.33% 1 Missing and 1 partial ⚠️

📢 Thoughts on this report? Let us know!

@sleepyStick
sleepyStick marked this pull request as ready for review September 24, 2026 21:54
@sleepyStick
sleepyStick requested a review from a team as a code owner September 24, 2026 21:54
@sleepyStick
sleepyStick requested review from aclark4life and a lite review from Copilot and removed request for Copilot September 24, 2026 21:54

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Direct non-SRV URI parsing can silently ignore the validator, and polling behavior documentation needs clarification.

Get a fresh assessment by requesting another Copilot review.

Review effort: Lite
Findings: 1 Low severity

Open (1)
What changed in this PR

Introduces configurable SRV host validation and improves polling behavior for invalid DNS records.

Changes:

  • Adds srv_host_validator to synchronous and asynchronous clients.
  • Skips invalid hosts during SRV polling and logs them.
  • Updates suffix handling, tests, telemetry, and changelog documentation.
File Summary
test/​unified_format.py Updates synchronous test coverage and cleanup.
test/​test_srv_polling.py Tests synchronous SRV polling validation.
test/​test_dns.py Tests synchronous DNS validation and suffix behavior.
test/​asynchronous/​unified_format.py Updates asynchronous test coverage and cleanup.
test/​asynchronous/​test_srv_polling.py Tests asynchronous SRV polling validation.
test/​asynchronous/​test_dns.py Tests callback and suffix behavior; prose test naming needs correction.
pymongo/​synchronous/​uri_parser.py Synchronous URI parsing and validator propagation.
pymongo/​synchronous/​srv_resolver.py Synchronous SRV validation and polling filtering.
pymongo/​synchronous/​settings.py Stores synchronous validator configuration.
pymongo/​synchronous/​monitor.py Applies validation during synchronous polling.
pymongo/​synchronous/​mongo_client.py Exposes the synchronous validator option.
pymongo/​settings_shared.py Adds shared callback configuration.
pymongo/​public_suffix_list.dat Updates bundled suffix data.
pymongo/​common.py Validates callback options.
pymongo/​asynchronous/​uri_parser.py Propagates the validator; non-SRV direct parsing must reject it.
pymongo/​asynchronous/​srv_resolver.py Implements asynchronous validation and polling filtering.
pymongo/​asynchronous/​settings.py Stores asynchronous validator configuration.
pymongo/​asynchronous/​monitor.py Applies validation during asynchronous polling.
pymongo/​asynchronous/​mongo_client.py Exposes and documents the asynchronous validator option.
pymongo/​_telemetry.py Logs skipped invalid SRV hosts.
pymongo/​_psl.py Adds special-use suffix handling.
doc/​changelog.rst Documents the new functionality.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread pymongo/asynchronous/mongo_client.py Outdated
Comment on lines +477 to +480
reject it. Rejecting a host raises
:exc:`~pymongo.errors.ConfigurationError`, as does an exception raised by
the callback itself. Use this when the set of acceptable hosts cannot be
expressed as a single suffix::

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think users need to know the difference between initial discovery and polling so I believe this suggestion should be ignored.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True but probably doesn't hurt to clarify "During initial discovery" …

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done in 07df266

elif self.__srv_allowed_hosts_suffix is not None:
if not srv_host.endswith(self.__srv_allowed_hosts_suffix):
raise ConfigurationError(f"Invalid SRV host: {srv_host}")
else:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we miss this branch if the conditional on line 155 is True.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sorry i'm not sure i understand what you mean by this comment -- it is possible to enter the else conditional and there is test coverage for all three branches. If we're referring to the identical hostname check, that's intentional per the spec. Can you clarify what you mean?

Comment thread doc/changelog.rst Outdated
connection string. See the
:class:`~pymongo.synchronous.mongo_client.MongoClient` and
:class:`~pymongo.asynchronous.mongo_client.AsyncMongoClient` documentation for
security considerations (`PYTHON-5814`_).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be PYTHON-6080 ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, but also current iris isn't sure why past iris put a ticket there so i'm going to just remove the ticket reference entirely.

Comment thread pymongo/asynchronous/srv_resolver.py Outdated
self.__srv_allowed_hosts_suffix
):
self.__srv_host_validator = srv_host_validator
# parse_uri() can this constructor independently of AsyncMongoClient.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"can … this constructor"?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah, oops, fixed in 07df266. thanks!

Comment thread pymongo/synchronous/srv_resolver.py Outdated
self.__srv_allowed_hosts_suffix
):
self.__srv_host_validator = srv_host_validator
# parse_uri() can this constructor independently of MongoClient.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"can … this constructor"?

Comment thread pymongo/_psl.py Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does the caller reject it? Looks like a..b becomes .a..b

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sorry I think this was a case of bad comment -- realistically DNS won't return an SRV target with an empty label, so even if a user passes it in, it would fail verification. I've updated the comment appropriately in 07df266. Thanks!

Comment thread test/asynchronous/test_srv_polling.py Outdated
nodes = []
for node in self.nodelist_callback():
try:
resolver._validate_host(node[0].rstrip(".").lower())

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the mock calls _validate_host and drops rejected hosts here, tests 14 and 15 would still pass if _get_srv_response_and_hosts stopped filtering for some reason.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah good catch -- i've reworked this in 07df266 to only mock the DNS answer so the real filtering happens now!

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants