LSP icon indicating copy to clipboard operation
LSP copied to clipboard

Provide `Transport` as parameter when invoking `plugin.on_post_start`

Open twwildey opened this issue 8 months ago • 9 comments

Is your feature request related to a problem? Please describe.

When launching the LSP server for AWS Q Developer, this LSP server expects an AES encryption key to be written on stdin - before any other messages - in order to encrypt AWS credentials that would later be sent by the LSP client. This ensures plaintext AWS credentials are not persisted in logs by LSP clients. One can observe the need to receive an AES encryption key before any other messages by reading the following code in the LSP server for AWS Q Developer:

  1. https://github.com/aws/language-servers/blob/main/app/aws-lsp-codewhisperer-binary/src/iam-standalone.ts
  2. https://github.com/aws/language-server-runtimes/blob/7e44d7516d55797cf1f7e5614dfa9fce2236e7f3/runtimes/runtimes/standalone.ts#L90C13-L90C34

Describe the solution you'd like

Within an LSP plugin, the only opportunity for the plugin to access the process for the underlying Transport of an LSP server - before any messages are sent to it - is within the on_post_start hook for an AbstractPlugin:

  1. https://github.com/sublimelsp/LSP/blob/fc5a7c75c8cec2e6765e218f7df980315c5c9ff3/plugin/core/windows.py#L282
  2. https://github.com/sublimelsp/LSP/blob/cd7cb682e634657c63105b906bacda99611846fd/plugin/core/sessions.py#L943

However, in order for the AbstractPlugin to access the underlying process in on_post_start, it needs to receive the Transport instance created for the Session. Since the initialize_async method on Session will send the initialize message to the LSP server, there is no other opportunity for the LSP plugin to provide an AES key to the LSP server before other messages are sent:

  1. https://github.com/sublimelsp/LSP/blob/fc5a7c75c8cec2e6765e218f7df980315c5c9ff3/plugin/core/windows.py#L284
  2. https://github.com/sublimelsp/LSP/blob/cd7cb682e634657c63105b906bacda99611846fd/plugin/core/sessions.py#L1510

Given these constraints, it seems the best way to support the LSP server for AWS Q Developer is to provide the Transport instance that the plugin will use as an additional (keyword?) parameter to the on_post_start hook.

Describe alternatives you've considered

In order to get around this issue, I found that transports.py stores a singleton Weakset of processes launched by each Transport instance in a variable called _subprocesses: https://github.com/sublimelsp/LSP/blob/cd7cb682e634657c63105b906bacda99611846fd/plugin/core/transports.py#L285

Currently, I am importing this _subprocesses from transports.py and finding the "most recent" subprocess that the LSP plugin has not seen before. However, this is very brittle and relies on internal implementation details. It would be better for the on_post_start hook to explicitly provide the Transport instance, so there's no possible ambiguity in resolving the correct process to write the AWS encryption key to.

Additional context

I am authoring an LSP plugin for AWS Q Developer at this time, and Amazon will be unwilling to compromise the security profile of this LSP plugin by sending unencrypted AWS credentials over LSP messages to the LSP server for AWS Q Developer. I kindly ask that we consider this concern critical to the success of new LSP plugins that will be meaningful to Sublime Text users.

I would be happy to author a PR for this issue as well, but I'd like to get alignment with the community first before doing so, in order to address any material concerns they may have.

twwildey avatar Jun 08 '24 20:06 twwildey