From 9a89ebeae15d629bcad4e3d319fef0f3f5963e65 Mon Sep 17 00:00:00 2001 From: Kevin Mas Ruiz Date: Fri, 2 Oct 2026 20:08:23 +0200 Subject: [PATCH] fix(mongodb-runner): tolerate unauthorized metadata bookkeeping and clean up on failed start MONGOSH-3619 --- packages/mongodb-runner/src/mongocluster.ts | 13 ++++--- .../mongodb-runner/src/mongoserver.spec.ts | 35 ++++++++++++++++++- packages/mongodb-runner/src/mongoserver.ts | 18 +++++++++- 3 files changed, 57 insertions(+), 9 deletions(-) diff --git a/packages/mongodb-runner/src/mongocluster.ts b/packages/mongodb-runner/src/mongocluster.ts index 7ad00f452..6528e3424 100644 --- a/packages/mongodb-runner/src/mongocluster.ts +++ b/packages/mongodb-runner/src/mongocluster.ts @@ -574,13 +574,12 @@ export class MongoCluster extends EventEmitter { }, ); } catch (err) { - // Don't leak the compose project if cluster setup fails partway through. - if (cluster.dockerComposeProject) { - try { - await cluster.dockerComposeProject.close(); - } catch { - /* ignore */ - } + // Don't leak servers or the compose project if cluster setup fails + // partway through. + try { + await cluster.close(); + } catch { + /* ignore */ } throw err; } diff --git a/packages/mongodb-runner/src/mongoserver.spec.ts b/packages/mongodb-runner/src/mongoserver.spec.ts index f20ee2bc8..aa78d5efa 100644 --- a/packages/mongodb-runner/src/mongoserver.spec.ts +++ b/packages/mongodb-runner/src/mongoserver.spec.ts @@ -1,9 +1,10 @@ import { expect } from 'chai'; import { MongoServer } from './mongoserver'; +import { MongoServerError } from 'mongodb'; import type { MongoClient } from 'mongodb'; import sinon from 'sinon'; -describe('MongoServer._ensureMatchingMetadataColl', function () { +describe('MongoServer', function () { let server: MongoServer; beforeEach(function () { @@ -77,4 +78,36 @@ describe('MongoServer._ensureMatchingMetadataColl', function () { expect(commandStub).to.have.been.calledOnce; }); + + describe('assertHasInsertedLocalMetadata', function () { + it('does not throw when the server rejects the metadata write as unauthorized', async function () { + // Servers started with --auth but without users the runner can use cannot + // be reached for bookkeeping, which must not fail cluster startup. + sinon.stub(server, 'withClient').rejects( + new MongoServerError({ + code: 13, + codeName: 'Unauthorized', + message: + 'not authorized on local to execute command { find: "mongodbrunner" }', + }), + ); + + await server.assertHasInsertedLocalMetadata(); + }); + + it('throws when the metadata population fails for any other reason', async function () { + sinon + .stub(server, 'withClient') + .rejects(new MongoServerError({ code: 6, message: 'host not found' })); + + let err: Error | undefined; + try { + await server.assertHasInsertedLocalMetadata(); + } catch (e) { + err = e as Error; + } + + expect(err).to.be.an.instanceOf(MongoServerError); + }); + }); }); diff --git a/packages/mongodb-runner/src/mongoserver.ts b/packages/mongodb-runner/src/mongoserver.ts index 0dc4ec267..277789770 100644 --- a/packages/mongodb-runner/src/mongoserver.ts +++ b/packages/mongodb-runner/src/mongoserver.ts @@ -10,7 +10,7 @@ import { } from './mongologreader'; import { Readable } from 'stream'; import type { Document, MongoClientOptions } from 'mongodb'; -import { MongoClient } from 'mongodb'; +import { MongoClient, MongoServerError } from 'mongodb'; import path from 'path'; import { EventEmitter, once } from 'events'; import { @@ -99,6 +99,13 @@ function getKeyFileOption(args?: string[] | undefined): string | undefined { return arg?.split('=')[1]; } +function isUnauthorizedError(err: unknown): boolean { + return ( + err instanceof MongoServerError && + (err.codeName === 'Unauthorized' || Number(err.code) === 13) + ); +} + export class MongoServer extends EventEmitter { public uuid: string = uuid(); private buildInfo?: Document; @@ -629,6 +636,15 @@ export class MongoServer extends EventEmitter { if (!this.hasInsertedMetadataCollEntry) { debug('populating metadata collection entry after initial setup'); const err = await this._populateBuildInfo('insert-new'); + if (err && isUnauthorizedError(err)) { + // Servers started with --auth but without users the runner can use + // cannot be reached for bookkeeping; treat it as best-effort. + debug( + 'cannot populate metadata collection entry, server requires authentication', + err, + ); + return; + } if (err && !this.isMongos && !this.isConfigSvr && !this.isDSC) throw err; } if (!this.buildInfo) {