diff --git a/src/Explorer/Tabs/CloudShellTab/ShellTypes/AbstractShellHandler.test.tsx b/src/Explorer/Tabs/CloudShellTab/ShellTypes/AbstractShellHandler.test.tsx index fb89bd435..1f2d36c47 100644 --- a/src/Explorer/Tabs/CloudShellTab/ShellTypes/AbstractShellHandler.test.tsx +++ b/src/Explorer/Tabs/CloudShellTab/ShellTypes/AbstractShellHandler.test.tsx @@ -1,4 +1,4 @@ -import { AbstractShellHandler, DISABLE_HISTORY, START_MARKER, EXIT_COMMAND } from "./AbstractShellHandler"; +import { AbstractShellHandler, DISABLE_HISTORY, EXIT_COMMAND, START_MARKER } from "./AbstractShellHandler"; // Mock implementation for testing class MockShellHandler extends AbstractShellHandler { @@ -18,8 +18,8 @@ class MockShellHandler extends AbstractShellHandler { return "mock-endpoint"; } - getTerminalSuppressedData(): string { - return "suppressed-data"; + getTerminalSuppressedData(): string[] { + return ["suppressed-data"]; } } @@ -90,7 +90,7 @@ describe("AbstractShellHandler", () => { }); it("should return the terminal suppressed data", () => { - expect(shellHandler.getTerminalSuppressedData()).toBe("suppressed-data"); + expect(shellHandler.getTerminalSuppressedData()).toEqual(["suppressed-data"]); }); }); }); diff --git a/src/Explorer/Tabs/CloudShellTab/ShellTypes/AbstractShellHandler.tsx b/src/Explorer/Tabs/CloudShellTab/ShellTypes/AbstractShellHandler.tsx index 9b550d190..9b5fef0a1 100644 --- a/src/Explorer/Tabs/CloudShellTab/ShellTypes/AbstractShellHandler.tsx +++ b/src/Explorer/Tabs/CloudShellTab/ShellTypes/AbstractShellHandler.tsx @@ -15,6 +15,12 @@ export const DISABLE_HISTORY = `set +o history`; */ export const EXIT_COMMAND = ` printf "\\033[1;31mSession ended. Please close this tab and initiate a new shell session if needed.\\033[0m\\n" && disown -a && exit`; +/** + * This command runs mongosh in no-database and quiet mode, + * and evaluates the `disableTelemetry()` function to turn off telemetry collection. + */ +export const DISABLE_TELEMETRY_COMMAND = `mongosh --nodb --quiet --eval "disableTelemetry()"`; + /** * Abstract class that defines the interface for shell-specific handlers * in the CloudShell terminal implementation. Each supported shell type @@ -31,7 +37,8 @@ export abstract class AbstractShellHandler { abstract getShellName(): string; abstract getSetUpCommands(): string[]; abstract getConnectionCommand(): string; - abstract getTerminalSuppressedData(): string; + abstract getTerminalSuppressedData(): string[]; + updateTerminalData?(data: string): string; /** * Constructs the complete initialization command sequence for the shell. @@ -77,7 +84,7 @@ export abstract class AbstractShellHandler { * is not already present in the environment. */ protected mongoShellSetupCommands(): string[] { - const PACKAGE_VERSION: string = "2.5.0"; + const PACKAGE_VERSION: string = "2.5.5"; return [ "if ! command -v mongosh &> /dev/null; then echo '⚠️ mongosh not found. Installing...'; fi", `if ! command -v mongosh &> /dev/null; then curl -LO https://downloads.mongodb.com/compass/mongosh-${PACKAGE_VERSION}-linux-x64.tgz; fi`, @@ -85,7 +92,7 @@ export abstract class AbstractShellHandler { `if ! command -v mongosh &> /dev/null; then mkdir -p ~/mongosh/bin && mv mongosh-${PACKAGE_VERSION}-linux-x64/bin/mongosh ~/mongosh/bin/ && chmod +x ~/mongosh/bin/mongosh; fi`, `if ! command -v mongosh &> /dev/null; then rm -rf mongosh-${PACKAGE_VERSION}-linux-x64 mongosh-${PACKAGE_VERSION}-linux-x64.tgz; fi`, "if ! command -v mongosh &> /dev/null; then echo 'export PATH=$HOME/mongosh/bin:$PATH' >> ~/.bashrc; fi", - "source ~/.bashrc", + "if ! command -v mongosh &> /dev/null; then source ~/.bashrc; fi", ]; } } diff --git a/src/Explorer/Tabs/CloudShellTab/ShellTypes/CassandraShellHandler.test.tsx b/src/Explorer/Tabs/CloudShellTab/ShellTypes/CassandraShellHandler.test.tsx index 9bf4b3aa7..9b6c71865 100644 --- a/src/Explorer/Tabs/CloudShellTab/ShellTypes/CassandraShellHandler.test.tsx +++ b/src/Explorer/Tabs/CloudShellTab/ShellTypes/CassandraShellHandler.test.tsx @@ -94,7 +94,7 @@ describe("CassandraShellHandler", () => { }); test("should return the correct terminal suppressed data", () => { - expect(handler.getTerminalSuppressedData()).toBe(""); + expect(handler.getTerminalSuppressedData()).toEqual([""]); }); test("should include the correct package version in setup commands", () => { diff --git a/src/Explorer/Tabs/CloudShellTab/ShellTypes/CassandraShellHandler.tsx b/src/Explorer/Tabs/CloudShellTab/ShellTypes/CassandraShellHandler.tsx index edd878bb4..3ec4f4a43 100644 --- a/src/Explorer/Tabs/CloudShellTab/ShellTypes/CassandraShellHandler.tsx +++ b/src/Explorer/Tabs/CloudShellTab/ShellTypes/CassandraShellHandler.tsx @@ -41,7 +41,7 @@ export class CassandraShellHandler extends AbstractShellHandler { return `cqlsh ${getHostFromUrl(this._endpoint)} 10350 -u ${dbName} -p ${this._key} --ssl`; } - public getTerminalSuppressedData(): string { - return ""; + public getTerminalSuppressedData(): string[] { + return [""]; } } diff --git a/src/Explorer/Tabs/CloudShellTab/ShellTypes/MongoShellHandler.test.tsx b/src/Explorer/Tabs/CloudShellTab/ShellTypes/MongoShellHandler.test.tsx index 25395322f..40bb37c22 100644 --- a/src/Explorer/Tabs/CloudShellTab/ShellTypes/MongoShellHandler.test.tsx +++ b/src/Explorer/Tabs/CloudShellTab/ShellTypes/MongoShellHandler.test.tsx @@ -69,7 +69,7 @@ describe("MongoShellHandler", () => { expect(Array.isArray(commands)).toBe(true); expect(commands.length).toBe(7); - expect(commands[1]).toContain("mongosh-2.5.0-linux-x64.tgz"); + expect(commands[1]).toContain("mongosh-2.5.5-linux-x64.tgz"); }); }); @@ -91,7 +91,7 @@ describe("MongoShellHandler", () => { const command = mongoShellHandler.getConnectionCommand(); expect(command).toBe( - "mongosh mongodb://test-mongo.documents.azure.com:10255?appName=CosmosExplorerTerminal --username test-account --password test-key --tls --tlsAllowInvalidCertificates", + 'mongosh --nodb --quiet --eval "disableTelemetry()" && mongosh mongodb://test-mongo.documents.azure.com:10255?appName=CosmosExplorerTerminal --username test-account --password test-key --tls --tlsAllowInvalidCertificates', ); expect(CommonUtils.getHostFromUrl).toHaveBeenCalledWith("https://test-mongo.documents.azure.com:443/"); @@ -124,7 +124,7 @@ describe("MongoShellHandler", () => { describe("getTerminalSuppressedData", () => { it("should return the correct warning message", () => { - expect(mongoShellHandler.getTerminalSuppressedData()).toBe("Warning: Non-Genuine MongoDB Detected"); + expect(mongoShellHandler.getTerminalSuppressedData()).toEqual(["Warning: Non-Genuine MongoDB Detected"]); }); }); }); diff --git a/src/Explorer/Tabs/CloudShellTab/ShellTypes/MongoShellHandler.tsx b/src/Explorer/Tabs/CloudShellTab/ShellTypes/MongoShellHandler.tsx index d15c42017..dfebe6831 100644 --- a/src/Explorer/Tabs/CloudShellTab/ShellTypes/MongoShellHandler.tsx +++ b/src/Explorer/Tabs/CloudShellTab/ShellTypes/MongoShellHandler.tsx @@ -1,6 +1,6 @@ import { userContext } from "../../../../UserContext"; import { getHostFromUrl } from "../Utils/CommonUtils"; -import { AbstractShellHandler } from "./AbstractShellHandler"; +import { AbstractShellHandler, DISABLE_TELEMETRY_COMMAND } from "./AbstractShellHandler"; export class MongoShellHandler extends AbstractShellHandler { private _key: string; @@ -29,6 +29,8 @@ export class MongoShellHandler extends AbstractShellHandler { return "echo 'Database name not found.'"; } return ( + DISABLE_TELEMETRY_COMMAND + + " && " + "mongosh mongodb://" + getHostFromUrl(this._endpoint) + ":10255?appName=" + @@ -41,7 +43,7 @@ export class MongoShellHandler extends AbstractShellHandler { ); } - public getTerminalSuppressedData(): string { - return "Warning: Non-Genuine MongoDB Detected"; + public getTerminalSuppressedData(): string[] { + return ["Warning: Non-Genuine MongoDB Detected"]; } } diff --git a/src/Explorer/Tabs/CloudShellTab/ShellTypes/PostgresShellHandler.test.tsx b/src/Explorer/Tabs/CloudShellTab/ShellTypes/PostgresShellHandler.test.tsx index ee4defaa0..54df59460 100644 --- a/src/Explorer/Tabs/CloudShellTab/ShellTypes/PostgresShellHandler.test.tsx +++ b/src/Explorer/Tabs/CloudShellTab/ShellTypes/PostgresShellHandler.test.tsx @@ -58,7 +58,7 @@ describe("PostgresShellHandler", () => { }); it("should return empty string for terminal suppressed data", () => { - expect(postgresShellHandler.getTerminalSuppressedData()).toBe(""); + expect(postgresShellHandler.getTerminalSuppressedData()).toEqual([""]); }); }); }); diff --git a/src/Explorer/Tabs/CloudShellTab/ShellTypes/PostgresShellHandler.tsx b/src/Explorer/Tabs/CloudShellTab/ShellTypes/PostgresShellHandler.tsx index c22d9d972..41ef5880b 100644 --- a/src/Explorer/Tabs/CloudShellTab/ShellTypes/PostgresShellHandler.tsx +++ b/src/Explorer/Tabs/CloudShellTab/ShellTypes/PostgresShellHandler.tsx @@ -57,7 +57,7 @@ export class PostgresShellHandler extends AbstractShellHandler { return `psql -h "${this._endpoint}" -p 5432 -d "citus" -U "${loginName}" --set=sslmode=require --set=application_name=${this.APP_NAME}`; } - public getTerminalSuppressedData(): string { - return ""; + public getTerminalSuppressedData(): string[] { + return [""]; } } diff --git a/src/Explorer/Tabs/CloudShellTab/ShellTypes/VCoreMongoShellHandler.test.tsx b/src/Explorer/Tabs/CloudShellTab/ShellTypes/VCoreMongoShellHandler.test.tsx index a5d4e1336..5c34a4978 100644 --- a/src/Explorer/Tabs/CloudShellTab/ShellTypes/VCoreMongoShellHandler.test.tsx +++ b/src/Explorer/Tabs/CloudShellTab/ShellTypes/VCoreMongoShellHandler.test.tsx @@ -45,7 +45,7 @@ describe("VCoreMongoShellHandler", () => { expect(Array.isArray(commands)).toBe(true); expect(commands.length).toBe(7); - expect(commands[1]).toContain("mongosh-2.5.0-linux-x64.tgz"); + expect(commands[1]).toContain("mongosh-2.5.5-linux-x64.tgz"); expect(commands[0]).toContain("mongosh not found"); }); @@ -57,7 +57,10 @@ describe("VCoreMongoShellHandler", () => { }); it("should return the correct terminal suppressed data", () => { - expect(vcoreMongoShellHandler.getTerminalSuppressedData()).toBe("Warning: Non-Genuine MongoDB Detected"); + expect(vcoreMongoShellHandler.getTerminalSuppressedData()).toEqual([ + "Warning: Non-Genuine MongoDB Detected", + "Telemetry is now disabled.", + ]); }); }); }); diff --git a/src/Explorer/Tabs/CloudShellTab/ShellTypes/VCoreMongoShellHandler.tsx b/src/Explorer/Tabs/CloudShellTab/ShellTypes/VCoreMongoShellHandler.tsx index 85641c5ff..c42598395 100644 --- a/src/Explorer/Tabs/CloudShellTab/ShellTypes/VCoreMongoShellHandler.tsx +++ b/src/Explorer/Tabs/CloudShellTab/ShellTypes/VCoreMongoShellHandler.tsx @@ -1,8 +1,13 @@ import { userContext } from "../../../../UserContext"; -import { AbstractShellHandler } from "./AbstractShellHandler"; +import { AbstractShellHandler, DISABLE_TELEMETRY_COMMAND } from "./AbstractShellHandler"; export class VCoreMongoShellHandler extends AbstractShellHandler { private _endpoint: string | undefined; + private _textFilterRules: string[] = [ + "For mongosh info see: https://www.mongodb.com/docs/mongodb-shell/", + "disableTelemetry() command", + "https://www.mongodb.com/legal/privacy-policy", + ]; constructor() { super(); @@ -23,10 +28,22 @@ export class VCoreMongoShellHandler extends AbstractShellHandler { } const userName = userContext.vcoreMongoConnectionParams.adminLogin; - return `mongosh "mongodb+srv://${userName}:@${this._endpoint}/?authMechanism=SCRAM-SHA-256&retrywrites=false&maxIdleTimeMS=120000&appName=${this.APP_NAME}"`; + + const connectionUri = `mongodb+srv://${userName}:@${this._endpoint}/?authMechanism=SCRAM-SHA-256&retrywrites=false&maxIdleTimeMS=120000&appName=${this.APP_NAME}`; + + return `${DISABLE_TELEMETRY_COMMAND} && mongosh "${connectionUri}"`; } - public getTerminalSuppressedData(): string { - return "Warning: Non-Genuine MongoDB Detected"; + public getTerminalSuppressedData(): string[] { + return ["Warning: Non-Genuine MongoDB Detected", "Telemetry is now disabled."]; + } + + updateTerminalData(content: string): string { + const updatedContent = content + .split("\n") + .filter((line) => !this._textFilterRules.some((part) => line.includes(part))) + .filter((line, idx, arr) => (arr.length > 3 && idx <= arr.length - 3 ? !["", "\r"].includes(line) : true)) // Filter out empty lines and carriage returns, but keep the last 3 lines if they exist + .join("\n"); + return updatedContent; } } diff --git a/src/Explorer/Tabs/CloudShellTab/Utils/AttachAddOn.tsx b/src/Explorer/Tabs/CloudShellTab/Utils/AttachAddOn.tsx index 75a19c1aa..0fbdc0aee 100644 --- a/src/Explorer/Tabs/CloudShellTab/Utils/AttachAddOn.tsx +++ b/src/Explorer/Tabs/CloudShellTab/Utils/AttachAddOn.tsx @@ -135,11 +135,13 @@ export class AttachAddon implements ITerminalAddon { } if (this._allowTerminalWrite) { + const updatedData = this._shellHandler?.updateTerminalData(data) ?? data; const suppressedData = this._shellHandler?.getTerminalSuppressedData(); - const hasSuppressedData = suppressedData && suppressedData.length > 0; - if (!hasSuppressedData || !data.includes(suppressedData)) { - terminal.write(data); + const shouldNotWrite = suppressedData.filter(Boolean).some((item) => updatedData.includes(item)); + + if (!shouldNotWrite) { + terminal.write(updatedData); } }