Skip to content

fix(plugin-mongodb): pin the auth database and create databases that persist - #1974

Merged
datlechin merged 2 commits into
mainfrom
fix-1970-mongodb-auth-source
Jul 27, 2026
Merged

fix(plugin-mongodb): pin the auth database and create databases that persist#1974
datlechin merged 2 commits into
mainfrom
fix-1970-mongodb-auth-source

Conversation

@datlechin

@datlechin datlechin commented Jul 27, 2026

Copy link
Copy Markdown
Member

Fixes #1970.

Creating a MongoDB database put the connection into an error state showing [11] Authentication failed, with no way back. Creating the database was the trigger, not the bug. There are two independent defects.

1. Browsing a MongoDB database re-authenticated against that database

MetadataConnectionPool.openEntry opens a separate driver per database. It copied the session's connection, set connection.database = key.database, and connected. MongoDB uses the default supportsConnectionPooling: true, so this ran on every sidebar refresh.

That fabricated connection reached MongoDBConnection.buildUri(), which set authSource to the target database whenever "Auth Database" was blank and the connection was not SRV. libmongoc sent the SCRAM handshake to a database the user does not exist in and returned MONGOC_ERROR_CLIENT_AUTHENTICATE (11).

Verified against a live MongoDB 7 server:

mongodb://u:p@host/newdb?authSource=newdb  -> Authentication failed
mongodb://u:p@host/newdb?authSource=admin  -> { ok: 1 }

Creating a database auto-switches to it, which triggers the refresh, which opens the poisoned connection. Any database switch broke the same way on an authenticated server with a blank Auth Database, not just a freshly created one.

Fix. The pool no longer rewrites the connection's database for engines where that changes who you authenticate as. A pure planConnection decides: connect with the configured database, then switchDatabase to the target, the same shape DatabaseManager+Health.restoreSchemaAndDatabase already uses on every reconnect. Every other engine keeps today's behaviour byte for byte.

This is gated by a new capability, authenticationIsDatabaseScoped, defaulting to false and set only on MongoDB. It names the reason rather than the mechanism: the credentials authenticate against the database given at connect time. I deliberately did not reuse requiresReconnectForDatabaseSwitch, which is also false for MySQL, MariaDB, SQL Server, ClickHouse, Cassandra, Trino, Snowflake and others. "Can switch without reconnecting" is a different property from "the connect-time database does not change your identity", and flipping the path for eleven other engines buys nothing here.

On the plugin side, authSource now resolves through MongoDBAuthSourceResolver (explicit value, then the configured database, then admin) and is computed once at construction, so a later switchDatabase can never influence it.

Because the app-side change restores what the plugin is handed, users get the fix from the app update alone, on whatever MongoDB plugin version they already have installed.

2. Create database deleted the database it created

createDatabase inserted into __tablepro_init and then dropped it. MongoDB removes a database when its last collection goes. Verified live: present after the insert, gone after the drop. So "New Database" produced nothing even before the auth failure.

after insert  -> ["admin","config","local","tp_created"]
after drop    -> ["admin","config","local"]

Fix. createDatabase runs {"create": "<collection>"} and leaves the collection in place. An empty collection is enough to keep the database in listDatabases, verified on 7.0.39, so no placeholder document is needed. The dialog now asks for a required First Collection, which is what MongoDB Compass does and for the same reason. MongoDBNameValidator checks MongoDB's documented name limits and the sheet's existing banner shows the message inline.

3. The error message

A MongoDB auth failure now reads:

Authentication failed for user 'app' against database 'admin'. Check the username, password, and Auth Database in the connection settings.

instead of [11] Authentication failed, which is a raw libmongoc enum ordinal and the shape the HIG calls out by name ("Avoid writing a title that doesn't convey useful information, like 'Error 329347 occurred'"). The domain and code go to OSLog.

PluginKit ABI: additive, no version bump

PluginCreateDatabaseFormSpec.FieldKind is @frozen, so a new case would be a breaking change forcing a bump and a re-release of every registry plugin. Instead the spec gains a nested TextInput type, a textInputs property, and a new init overload, with the existing init's signature untouched.

scripts/check-pluginkit-abi.sh origin/main reports additions only: the new TextInput, the new property, the new init. Nothing removed, no signature changed, FieldKind still has exactly its two cases. Needs the abi-additive label.

The plugin marks the field required while still defaulting the collection name to the database name when the value is absent, so an older app that does not render the field degrades quietly. The app and plugin releases need no ordering.

Tests

  • MongoDBAuthSourceResolverTests: the fallback chain, including that SRV always uses admin.
  • MongoDBNameValidatorTests: every forbidden character, byte-counted length limits, the system. prefix, the 255-byte namespace boundary.
  • MongoDBCreateDatabasePlanTests: collection-name resolution, trimming, and both fallback paths, plus that the legacy form-spec init declares no text inputs.
  • MetadataConnectionPoolPlanTests: the plan for a database-scoped engine, the redundant-switch case, a blank configured database, and that every other engine is unchanged.
  • MetadataConnectionPoolTests: a driver that cannot switch databases is rejected rather than silently serving the wrong one.

35 tests pass. swiftlint lint --strict reports 0 violations in 1210 files. The MongoDBDriver target builds.

Release

The app-side changes ship with the next app release and fix the reported failure on their own. The plugin changes ship on the next plugin-mongodb-v* tag. No other plugin needs re-releasing.

Out of scope

  • Sidebar recovery affordances (retry, reconnect, edit connection on a failed node) and mapping driver errors onto NSError's failure-reason and recovery-suggestion tiers. Right, but a separate feature across every engine.
  • SurrealDB declares requiresReconnectForDatabaseSwitch: false and has database-scoped credentials, so it may have the same latent problem. Unverified, worth its own issue.

Second commit: an unrelated flaky test this PR exposed

The first CI run failed on SSHChannelRelay / "Channel close terminates the relay", which this change does not touch. It is a pre-existing double-close in the test helper.

SocketPair.close() closes both descriptors, and localHangup and transportHangup each call closeB() first and then close() through their defer, so b is closed twice. The suite runs in parallel, so the second close releases a descriptor number the kernel may have already handed to a socket another test is polling. That test then sees a hangup it never caused, which is exactly the reported symptom: channelClosed expected .channelClosed and got .localClosed.

SocketPair now tracks each descriptor and closes it once, and a failed socketpair() no longer leaves the fds at 0, where closing them would have closed stdin.

Reproduced locally at 1 failure in 5 runs before the fix, and 0 in 10 after. Kept as its own commit so it can be split out.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@datlechin datlechin added the abi-additive PluginKit ABI diff reviewed as additive; no version bump needed label Jul 27, 2026
@mintlify

mintlify Bot commented Jul 27, 2026

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
TablePro 🟢 Ready View Preview Jul 27, 2026, 1:03 PM

💡 Tip: Enable Workflows to automatically generate PRs for you.

@datlechin
datlechin merged commit e244cae into main Jul 27, 2026
2 checks passed
@datlechin
datlechin deleted the fix-1970-mongodb-auth-source branch July 27, 2026 13:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

abi-additive PluginKit ABI diff reviewed as additive; no version bump needed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Imposible work with MongoDB databases

1 participant