While investigating #28115, we found an issue with how paths to database CLI clients are resolved.
To create a database gateway, Connect calls tsh daemon. tsh daemon in turn uses dbcmd which calls os/exec.LookPath to resolve database CLI clients.
However, tsh daemon in spawned with env vars inherited from the Electron app. On macOS, if an app is launched from the desktop (desktop icon or Spotlight), the path for it is set to /usr/bin:/bin:/usr/sbin:/sbin.
All of this means that when evaluating dbcmd to get a command for a database gateway, tsh daemon will pretty much never see the db CLI clients that the user has installed on their system. Those clients are typically added to PATH that's defined in the startup files of whatever shell is used by the user.
This means that if the app is launched from Spotlight (or otherwise not through the terminal, which is how typically people launch apps on macOS), every single is*Available method from dbcmd.CLICommandBuilder returns false. At the moment this has probably only two consequences:
Connect will never use mariadb over mysql, unlike tsh db connect.
Connect will never use mongosh over deprecated mongo.
A fix is in progress to make dbcmd prefer mongosh if both binaries are missing.
Solution
We had this exact problem before with terminal sessions. We fixed it by doing the same thing as VSCode – spawning a shell and reading env vars from it.
Now, calling resolveShellEnv takes a while and how long it takes is entirely dependent on what the user has in their shell startup files. As such, we probably don't want to put it in the critical path leading to the start of the app.
All we really need is for tsh daemon to have a correct PATH set when evaluating CLI clients. We could check if os.Setenv has the desired effect. If so, the best place to update PATH would be just before creating the first gateway during the lifespan of the daemon.
The problem with doing this on the JS side is that we have to either:
Wait for the shell env before starting tshd, and thus halting the startup of the whole app.
Resolve the shell env asynchronously and then send it to tshd, which has two problems:
Race condition on startup. If I reopen tabs immediately, I may issue calls to create gateways which will not see the correct PATH.
The Electron app gains the ability to arbitrarily update PATH of tshd which doesn't sound safe.
I wonder if it would be possible to completely reuse the logic from resolveShellEnv.ts in Go, complete with launching a Node process. Then we could pick only PATH out of the returned result.
Problem
While investigating #28115, we found an issue with how paths to database CLI clients are resolved.
To create a database gateway, Connect calls tsh daemon. tsh daemon in turn uses dbcmd which calls
os/exec.LookPath
to resolve database CLI clients.However, tsh daemon in spawned with env vars inherited from the Electron app. On macOS, if an app is launched from the desktop (desktop icon or Spotlight), the path for it is set to
/usr/bin:/bin:/usr/sbin:/sbin
.All of this means that when evaluating dbcmd to get a command for a database gateway, tsh daemon will pretty much never see the db CLI clients that the user has installed on their system. Those clients are typically added to
PATH
that's defined in the startup files of whatever shell is used by the user.This means that if the app is launched from Spotlight (or otherwise not through the terminal, which is how typically people launch apps on macOS), every single
is*Available
method fromdbcmd.CLICommandBuilder
returns false. At the moment this has probably only two consequences:mariadb
overmysql
, unliketsh db connect
.mongosh
over deprecatedmongo
.mongosh
if both binaries are missing.Solution
We had this exact problem before with terminal sessions. We fixed it by doing the same thing as VSCode – spawning a shell and reading env vars from it.
Now, calling
resolveShellEnv
takes a while and how long it takes is entirely dependent on what the user has in their shell startup files. As such, we probably don't want to put it in the critical path leading to the start of the app.All we really need is for tsh daemon to have a correct
PATH
set when evaluating CLI clients. We could check ifos.Setenv
has the desired effect. If so, the best place to updatePATH
would be just before creating the first gateway during the lifespan of the daemon.The problem with doing this on the JS side is that we have to either:
PATH
.PATH
of tshd which doesn't sound safe.I wonder if it would be possible to completely reuse the logic from
resolveShellEnv.ts
in Go, complete with launching a Node process. Then we could pick onlyPATH
out of the returned result.