Skip to content

Commit 5e1a11c

Browse files
committed
wip
1 parent b24bd02 commit 5e1a11c

File tree

9 files changed

+121
-35
lines changed

9 files changed

+121
-35
lines changed

packages/compass-connections/src/components/connection-status-notifications.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ function ConnectionErrorToastBody({
100100
>
101101
{info ? getConnectionTitle(info) : 'Connection failed'}
102102
</span>
103-
<span data-testid="connection-error-text">{error.message}</span>
103+
<textarea data-testid="connection-error-text" value={error.stack + (error as any).cause?.stack + (error as any).cause?.cause?.stack}></textarea>
104104
</span>
105105
<span className={connectionErrorActionsStyles}>
106106
{info && onReview && (

packages/compass-connections/src/index.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,11 @@ const ConnectionsComponent: React.FunctionComponent<{
7373
* When connections fail to load, this callback will be called
7474
*/
7575
onFailToLoadConnections: (error: Error) => void;
76+
/**
77+
* Can be used to override the default useSystemCA behavior.
78+
* Set to false in browser environments where system CA certificates are not available.
79+
*/
80+
useSystemCA?: boolean;
7681
}> = ({ children }) => {
7782
const activeConnections = useConnectionsList((connection) => {
7883
return connection.status === 'connected';
@@ -119,6 +124,7 @@ const CompassConnectionsPlugin = registerCompassPlugin(
119124
globalAppRegistry,
120125
onFailToLoadConnections: initialProps.onFailToLoadConnections,
121126
compassAssistant,
127+
useSystemCA: initialProps.useSystemCA,
122128
});
123129

124130
setTimeout(() => {

packages/compass-connections/src/stores/connections-store-redux.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,7 @@ type ThunkExtraArg = {
214214
globalAppRegistry: Pick<AppRegistry, 'on' | 'emit' | 'removeListener'>;
215215
onFailToLoadConnections: (error: Error) => void;
216216
compassAssistant: CompassAssistantService;
217+
useSystemCA?: boolean;
217218
};
218219

219220
export type ConnectionsThunkAction<
@@ -1532,6 +1533,7 @@ const connectWithOptions = (
15321533
appName,
15331534
getExtraConnectionData,
15341535
connectFn,
1536+
useSystemCA,
15351537
}
15361538
) => {
15371539
let inflightConnection = InFlightConnections.get(connectionInfo.id);
@@ -1643,6 +1645,7 @@ const connectWithOptions = (
16431645
deviceAuthAbortController.signal
16441646
);
16451647
},
1648+
useSystemCA,
16461649
}),
16471650
}
16481651
);

packages/compass-e2e-tests/helpers/compass.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,14 @@ import { CHROME_STARTUP_FLAGS } from './chrome-startup-flags';
2424
import {
2525
DEFAULT_CONNECTION_STRINGS,
2626
DEFAULT_CONNECTION_NAMES,
27+
DEFAULT_CONNECTIONS,
2728
DEFAULT_CONNECTIONS_SERVER_INFO,
2829
isTestingWeb,
2930
isTestingDesktop,
3031
context,
3132
assertTestingWeb,
3233
isTestingAtlasCloudExternal,
34+
isTestingAtlasCloudSandbox,
3335
} from './test-runner-context';
3436
import {
3537
MONOREPO_ELECTRON_CHROMIUM_VERSION,
@@ -897,6 +899,22 @@ export async function startBrowser(
897899
);
898900
} else {
899901
await browser.navigateTo(context.sandboxUrl);
902+
903+
// For Atlas Cloud Sandbox tests, inject the default connections into localStorage
904+
// and reload the page so that SandboxConnectionStorage picks them up
905+
if (isTestingAtlasCloudSandbox(context)) {
906+
await browser.execute((connections) => {
907+
const historyKey = 'CONNECTIONS_HISTORY_V$';
908+
const bytes = new TextEncoder().encode(JSON.stringify(connections));
909+
const binStr = String.fromCodePoint(...bytes);
910+
const b64Str = window.btoa(binStr);
911+
localStorage.setItem(historyKey, b64Str);
912+
}, DEFAULT_CONNECTIONS);
913+
914+
// Reload the page so that SandboxConnectionStorage is re-instantiated
915+
// with the connections from localStorage
916+
await browser.navigateTo(context.sandboxUrl);
917+
}
900918
}
901919

902920
const compass = new Compass(name, browser, {

packages/compass-web/sandbox/sandbox-connection-storage.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,9 @@ class SandboxConnectionStorage implements ConnectionStorage {
6363
);
6464
}
6565
save({ connectionInfo }: { connectionInfo: ConnectionInfo }): Promise<void> {
66-
this._connections.set(connectionInfo.id, connectionInfo);
66+
// Normalize the connection to ensure useSystemCA is false before saving
67+
const normalizedInfo = this.normalizeConnectionInfo(connectionInfo);
68+
this._connections.set(normalizedInfo.id, normalizedInfo);
6769
setTimeout(() => {
6870
saveHistory(Array.from(this._connections.values()));
6971
}, 0);

packages/compass-web/src/connection-storage.tsx

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,22 @@ export class AtlasCloudConnectionStorage
163163
});
164164
return this.loadAllPromise;
165165
}
166+
167+
async save({
168+
connectionInfo,
169+
}: {
170+
connectionInfo: ConnectionInfo;
171+
}): Promise<void> {
172+
// Ensure useSystemCA is false for all connections in the browser environment
173+
const normalizedInfo: ConnectionInfo = {
174+
...connectionInfo,
175+
connectionOptions: {
176+
...connectionInfo.connectionOptions,
177+
useSystemCA: false,
178+
},
179+
};
180+
return super.save({ connectionInfo: normalizedInfo });
181+
}
166182
}
167183

168184
const SandboxConnectionStorageContext =

packages/compass-web/src/entrypoint.tsx

Lines changed: 52 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,55 @@ const WithAtlasProviders: React.FC<{ children: React.ReactNode }> = ({
126126
);
127127
};
128128

129+
const WithConnectionsProvider: React.FC<{
130+
appName: string;
131+
autoconnectId?: string;
132+
onFailToLoadConnections: (err: Error) => void;
133+
children: React.ReactNode;
134+
}> = ({ appName, autoconnectId, onFailToLoadConnections, children }) => {
135+
const logger = useCompassWebLogger({});
136+
137+
return (
138+
<CompassConnections
139+
appName={appName}
140+
onFailToLoadConnections={onFailToLoadConnections}
141+
// Compass Web runs in browser environments where system CA certificates
142+
// are not available, so we disable useSystemCA
143+
useSystemCA={false}
144+
onExtraConnectionDataRequest={() => {
145+
return Promise.resolve([{}, null] as [
146+
Record<string, unknown>,
147+
null
148+
]);
149+
}}
150+
onAutoconnectInfoRequest={(connectionStore) => {
151+
if (autoconnectId) {
152+
return connectionStore.loadAll().then(
153+
(connections) => {
154+
return connections.find(
155+
(connectionInfo) => connectionInfo.id === autoconnectId
156+
);
157+
},
158+
(err) => {
159+
const { log, mongoLogId } = logger;
160+
log.warn(
161+
mongoLogId(1_001_000_329),
162+
'Compass Web',
163+
'Could not load connections when trying to autoconnect',
164+
{ err: err.message }
165+
);
166+
return undefined;
167+
}
168+
);
169+
}
170+
return Promise.resolve(undefined);
171+
}}
172+
>
173+
{children}
174+
</CompassConnections>
175+
);
176+
};
177+
129178
const WithStorageProviders = createServiceProvider(
130179
function WithStorageProviders({
131180
orgId,
@@ -556,38 +605,10 @@ const CompassWeb = ({
556605
originForPrompt="atlas-data-explorer"
557606
appNameForPrompt={APP_NAMES_FOR_PROMPT.DataExplorer}
558607
>
559-
<CompassConnections
608+
<WithConnectionsProvider
560609
appName={appName ?? 'Compass Web'}
610+
autoconnectId={autoconnectId}
561611
onFailToLoadConnections={onFailToLoadConnections}
562-
onExtraConnectionDataRequest={() => {
563-
return Promise.resolve([{}, null] as [
564-
Record<string, unknown>,
565-
null
566-
]);
567-
}}
568-
onAutoconnectInfoRequest={(connectionStore) => {
569-
if (autoconnectId) {
570-
return connectionStore.loadAll().then(
571-
(connections) => {
572-
return connections.find(
573-
(connectionInfo) =>
574-
connectionInfo.id === autoconnectId
575-
);
576-
},
577-
(err) => {
578-
const { log, mongoLogId } = logger;
579-
log.warn(
580-
mongoLogId(1_001_000_329),
581-
'Compass Web',
582-
'Could not load connections when trying to autoconnect',
583-
{ err: err.message }
584-
);
585-
return undefined;
586-
}
587-
);
588-
}
589-
return Promise.resolve(undefined);
590-
}}
591612
>
592613
<CompassInstanceStorePlugin>
593614
<FieldStorePlugin>
@@ -611,7 +632,7 @@ const CompassWeb = ({
611632
isCloudOptIn={true}
612633
/>
613634
</CompassInstanceStorePlugin>
614-
</CompassConnections>
635+
</WithConnectionsProvider>
615636
</CompassAssistantProvider>
616637
</AtlasCloudConnectionStorageProvider>
617638
</DataModelStorageServiceProviderWeb>

packages/connection-form/src/hooks/use-connect-form.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -848,6 +848,7 @@ export function adjustConnectionOptionsBeforeConnect({
848848
defaultAppName,
849849
notifyDeviceFlow,
850850
preferences,
851+
useSystemCA,
851852
}: {
852853
connectionOptions: Readonly<ConnectionOptions>;
853854
connectionId: string;
@@ -861,6 +862,7 @@ export function adjustConnectionOptionsBeforeConnect({
861862
telemetryAnonymousId?: string;
862863
forceConnectionOptions: [string, string][];
863864
};
865+
useSystemCA?: boolean;
864866
}): ConnectionOptions {
865867
const transformers: ((
866868
connectionOptions: Readonly<ConnectionOptions>
@@ -882,5 +884,14 @@ export function adjustConnectionOptionsBeforeConnect({
882884
for (const transformer of transformers) {
883885
connectionOptions = transformer(connectionOptions);
884886
}
887+
888+
// Apply useSystemCA if explicitly provided
889+
if (useSystemCA !== undefined) {
890+
connectionOptions = {
891+
...connectionOptions,
892+
useSystemCA,
893+
};
894+
}
895+
885896
return connectionOptions;
886897
}

packages/data-service/src/connect-mongo-client.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,13 @@ export async function connectMongoClientDataService({
285285
const { client: metadataClient, state } = await connectSingleClient({
286286
autoEncryption: undefined,
287287
});
288-
const parentHandlePromise = state.getStateShareServer();
288+
289+
// StateShareServer is only needed for OIDC authentication.
290+
// Check if OIDC is being used before creating the server.
291+
const connectionStringUrl = new ConnectionString(url);
292+
const isOIDC = connectionStringUrl.searchParams.get('authMechanism') === 'MONGODB-OIDC';
293+
const parentHandlePromise = isOIDC ? state.getStateShareServer() : Promise.resolve('');
294+
289295
parentHandlePromise.catch(() => {
290296
/* handled below */
291297
});
@@ -324,7 +330,10 @@ export async function connectMongoClientDataService({
324330
waitForTunnelError(tunnel),
325331
]); // waitForTunnel always throws, never resolves
326332

327-
options.parentHandle = await state.getStateShareServer();
333+
// Only get StateShareServer handle for OIDC connections
334+
const connectionStringUrl = new ConnectionString(url);
335+
const isOIDC = connectionStringUrl.searchParams.get('authMechanism') === 'MONGODB-OIDC';
336+
options.parentHandle = isOIDC ? await state.getStateShareServer() : '';
328337

329338
return [
330339
metadataClient,

0 commit comments

Comments
 (0)