From ddc22bf9cfcd0f316d40b197b5c8f908fc74f04c Mon Sep 17 00:00:00 2001
From: Garrett Delfosse <garrett@coder.com>
Date: Mon, 24 Jun 2024 21:06:56 +0000
Subject: [PATCH 01/10] chore: use background hostname for admin tasks

---
 .../gateway/CoderRemoteConnectionHandle.kt     |  8 +++++++-
 .../com/coder/gateway/cli/CoderCLIManager.kt   | 18 +++++++++++++++++-
 .../steps/CoderWorkspaceProjectIDEStepView.kt  |  2 +-
 .../outputs/append-blank-newlines.conf         |  7 +++++++
 src/test/fixtures/outputs/append-blank.conf    |  7 +++++++
 .../fixtures/outputs/append-no-blocks.conf     |  7 +++++++
 .../fixtures/outputs/append-no-newline.conf    |  7 +++++++
 .../outputs/append-no-related-blocks.conf      |  7 +++++++
 .../fixtures/outputs/disable-autostart.conf    |  7 +++++++
 src/test/fixtures/outputs/extra-config.conf    |  9 +++++++++
 .../outputs/header-command-windows.conf        |  7 +++++++
 src/test/fixtures/outputs/header-command.conf  |  7 +++++++
 .../fixtures/outputs/multiple-workspaces.conf  | 14 ++++++++++++++
 .../fixtures/outputs/no-disable-autostart.conf |  7 +++++++
 .../outputs/replace-end-no-newline.conf        |  7 +++++++
 src/test/fixtures/outputs/replace-end.conf     |  7 +++++++
 .../replace-middle-ignore-unrelated.conf       |  7 +++++++
 src/test/fixtures/outputs/replace-middle.conf  |  7 +++++++
 src/test/fixtures/outputs/replace-only.conf    |  7 +++++++
 src/test/fixtures/outputs/replace-start.conf   |  7 +++++++
 20 files changed, 153 insertions(+), 3 deletions(-)

diff --git a/src/main/kotlin/com/coder/gateway/CoderRemoteConnectionHandle.kt b/src/main/kotlin/com/coder/gateway/CoderRemoteConnectionHandle.kt
index 6fa3ae7a..5d610107 100644
--- a/src/main/kotlin/com/coder/gateway/CoderRemoteConnectionHandle.kt
+++ b/src/main/kotlin/com/coder/gateway/CoderRemoteConnectionHandle.kt
@@ -141,7 +141,13 @@ class CoderRemoteConnectionHandle {
             port = 22
             authType = AuthType.OPEN_SSH
         }
-        val accessor = HighLevelHostAccessor.create(credentials, true)
+        val backgroundCredentials = RemoteCredentialsHolder().apply {
+            setHost(workspace.hostname)
+            userName = "coder"
+            port = 22
+            authType = AuthType.OPEN_SSH
+        }
+        val accessor = HighLevelHostAccessor.create(backgroundCredentials, true)
 
         // Deploy if we need to.
         val ideDir = this.deploy(workspace, accessor, indicator, timeout)
diff --git a/src/main/kotlin/com/coder/gateway/cli/CoderCLIManager.kt b/src/main/kotlin/com/coder/gateway/cli/CoderCLIManager.kt
index 96cb09ea..033f20b0 100644
--- a/src/main/kotlin/com/coder/gateway/cli/CoderCLIManager.kt
+++ b/src/main/kotlin/com/coder/gateway/cli/CoderCLIManager.kt
@@ -281,7 +281,15 @@ class CoderCLIManager(
                 transform = {
                     """
                     Host ${getHostName(deploymentURL, it)}
-                      ProxyCommand ${proxyArgs.joinToString(" ")} $it
+                      ProxyCommand CODER_SSH_USAGE_APP=jetbrains ${proxyArgs.joinToString(" ")} $it
+                      ConnectTimeout 0
+                      StrictHostKeyChecking no
+                      UserKnownHostsFile /dev/null
+                      LogLevel ERROR
+                      SetEnv CODER_SSH_SESSION_TYPE=JetBrains
+
+                    Host ${getBackgroundHostName(deploymentURL, it)}
+                      ProxyCommand CODER_SSH_USAGE_APP=disable ${proxyArgs.joinToString(" ")} $it
                       ConnectTimeout 0
                       StrictHostKeyChecking no
                       UserKnownHostsFile /dev/null
@@ -465,5 +473,13 @@ class CoderCLIManager(
         ): String {
             return "coder-jetbrains--$workspaceName--${url.safeHost()}"
         }
+
+        @JvmStatic
+        fun getBackgroundHostName(
+            url: URL,
+            workspaceName: String,
+        ): String {
+            return getHostName(url, workspaceName) + "--bg"
+        }
     }
 }
diff --git a/src/main/kotlin/com/coder/gateway/views/steps/CoderWorkspaceProjectIDEStepView.kt b/src/main/kotlin/com/coder/gateway/views/steps/CoderWorkspaceProjectIDEStepView.kt
index 334dc460..28bea76a 100644
--- a/src/main/kotlin/com/coder/gateway/views/steps/CoderWorkspaceProjectIDEStepView.kt
+++ b/src/main/kotlin/com/coder/gateway/views/steps/CoderWorkspaceProjectIDEStepView.kt
@@ -214,7 +214,7 @@ class CoderWorkspaceProjectIDEStepView(
                                     } else {
                                         IDECellRenderer(CoderGatewayBundle.message("gateway.connector.view.coder.connect-ssh"))
                                     }
-                                val executor = createRemoteExecutor(CoderCLIManager.getHostName(data.client.url, name))
+                                val executor = createRemoteExecutor(CoderCLIManager.getBackgroundHostName(data.client.url, name))
 
                                 if (ComponentValidator.getInstance(tfProject).isEmpty) {
                                     logger.info("Installing remote path validator...")
diff --git a/src/test/fixtures/outputs/append-blank-newlines.conf b/src/test/fixtures/outputs/append-blank-newlines.conf
index 9c75e87c..6a3ae5d3 100644
--- a/src/test/fixtures/outputs/append-blank-newlines.conf
+++ b/src/test/fixtures/outputs/append-blank-newlines.conf
@@ -10,4 +10,11 @@ Host coder-jetbrains--foo-bar--test.coder.invalid
   UserKnownHostsFile /dev/null
   LogLevel ERROR
   SetEnv CODER_SSH_SESSION_TYPE=JetBrains
+Host coder-jetbrains--foo-bar--test.coder.invalid--bg
+  ProxyCommand CODER_SSH_USAGE_APP=disable /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio foo-bar
+  ConnectTimeout 0
+  StrictHostKeyChecking no
+  UserKnownHostsFile /dev/null
+  LogLevel ERROR
+  SetEnv CODER_SSH_SESSION_TYPE=JetBrains
 # --- END CODER JETBRAINS test.coder.invalid
diff --git a/src/test/fixtures/outputs/append-blank.conf b/src/test/fixtures/outputs/append-blank.conf
index 566a8522..d2b4ec3c 100644
--- a/src/test/fixtures/outputs/append-blank.conf
+++ b/src/test/fixtures/outputs/append-blank.conf
@@ -6,4 +6,11 @@ Host coder-jetbrains--foo-bar--test.coder.invalid
   UserKnownHostsFile /dev/null
   LogLevel ERROR
   SetEnv CODER_SSH_SESSION_TYPE=JetBrains
+Host coder-jetbrains--foo-bar--test.coder.invalid--bg
+  ProxyCommand CODER_SSH_USAGE_APP=disable /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio foo-bar
+  ConnectTimeout 0
+  StrictHostKeyChecking no
+  UserKnownHostsFile /dev/null
+  LogLevel ERROR
+  SetEnv CODER_SSH_SESSION_TYPE=JetBrains
 # --- END CODER JETBRAINS test.coder.invalid
diff --git a/src/test/fixtures/outputs/append-no-blocks.conf b/src/test/fixtures/outputs/append-no-blocks.conf
index 11eeb7fe..25a33376 100644
--- a/src/test/fixtures/outputs/append-no-blocks.conf
+++ b/src/test/fixtures/outputs/append-no-blocks.conf
@@ -11,4 +11,11 @@ Host coder-jetbrains--foo-bar--test.coder.invalid
   UserKnownHostsFile /dev/null
   LogLevel ERROR
   SetEnv CODER_SSH_SESSION_TYPE=JetBrains
+Host coder-jetbrains--foo-bar--test.coder.invalid--bg
+  ProxyCommand CODER_SSH_USAGE_APP=disable /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio foo-bar
+  ConnectTimeout 0
+  StrictHostKeyChecking no
+  UserKnownHostsFile /dev/null
+  LogLevel ERROR
+  SetEnv CODER_SSH_SESSION_TYPE=JetBrains
 # --- END CODER JETBRAINS test.coder.invalid
diff --git a/src/test/fixtures/outputs/append-no-newline.conf b/src/test/fixtures/outputs/append-no-newline.conf
index 3dad453d..fe46f597 100644
--- a/src/test/fixtures/outputs/append-no-newline.conf
+++ b/src/test/fixtures/outputs/append-no-newline.conf
@@ -10,4 +10,11 @@ Host coder-jetbrains--foo-bar--test.coder.invalid
   UserKnownHostsFile /dev/null
   LogLevel ERROR
   SetEnv CODER_SSH_SESSION_TYPE=JetBrains
+Host coder-jetbrains--foo-bar--test.coder.invalid--bg
+  ProxyCommand CODER_SSH_USAGE_APP=disable /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio foo-bar
+  ConnectTimeout 0
+  StrictHostKeyChecking no
+  UserKnownHostsFile /dev/null
+  LogLevel ERROR
+  SetEnv CODER_SSH_SESSION_TYPE=JetBrains
 # --- END CODER JETBRAINS test.coder.invalid
diff --git a/src/test/fixtures/outputs/append-no-related-blocks.conf b/src/test/fixtures/outputs/append-no-related-blocks.conf
index 9b0b4c84..86c8d934 100644
--- a/src/test/fixtures/outputs/append-no-related-blocks.conf
+++ b/src/test/fixtures/outputs/append-no-related-blocks.conf
@@ -17,4 +17,11 @@ Host coder-jetbrains--foo-bar--test.coder.invalid
   UserKnownHostsFile /dev/null
   LogLevel ERROR
   SetEnv CODER_SSH_SESSION_TYPE=JetBrains
+Host coder-jetbrains--foo-bar--test.coder.invalid--bg
+  ProxyCommand CODER_SSH_USAGE_APP=disable /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio foo-bar
+  ConnectTimeout 0
+  StrictHostKeyChecking no
+  UserKnownHostsFile /dev/null
+  LogLevel ERROR
+  SetEnv CODER_SSH_SESSION_TYPE=JetBrains
 # --- END CODER JETBRAINS test.coder.invalid
diff --git a/src/test/fixtures/outputs/disable-autostart.conf b/src/test/fixtures/outputs/disable-autostart.conf
index a22e34d1..280b97d4 100644
--- a/src/test/fixtures/outputs/disable-autostart.conf
+++ b/src/test/fixtures/outputs/disable-autostart.conf
@@ -6,4 +6,11 @@ Host coder-jetbrains--foo--test.coder.invalid
   UserKnownHostsFile /dev/null
   LogLevel ERROR
   SetEnv CODER_SSH_SESSION_TYPE=JetBrains
+Host coder-jetbrains--foo--test.coder.invalid--bg
+  ProxyCommand CODER_SSH_USAGE_APP=disable /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio --disable-autostart foo
+  ConnectTimeout 0
+  StrictHostKeyChecking no
+  UserKnownHostsFile /dev/null
+  LogLevel ERROR
+  SetEnv CODER_SSH_SESSION_TYPE=JetBrains
 # --- END CODER JETBRAINS test.coder.invalid
diff --git a/src/test/fixtures/outputs/extra-config.conf b/src/test/fixtures/outputs/extra-config.conf
index 5dcff2c8..2fff157d 100644
--- a/src/test/fixtures/outputs/extra-config.conf
+++ b/src/test/fixtures/outputs/extra-config.conf
@@ -8,4 +8,13 @@ Host coder-jetbrains--extra--test.coder.invalid
   SetEnv CODER_SSH_SESSION_TYPE=JetBrains
   ServerAliveInterval 5
   ServerAliveCountMax 3
+Host coder-jetbrains--extra--test.coder.invalid--bg
+  ProxyCommand CODER_SSH_USAGE_APP=disable /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio extra
+  ConnectTimeout 0
+  StrictHostKeyChecking no
+  UserKnownHostsFile /dev/null
+  LogLevel ERROR
+  SetEnv CODER_SSH_SESSION_TYPE=JetBrains
+  ServerAliveInterval 5
+  ServerAliveCountMax 3
 # --- END CODER JETBRAINS test.coder.invalid
diff --git a/src/test/fixtures/outputs/header-command-windows.conf b/src/test/fixtures/outputs/header-command-windows.conf
index 4711c2ab..a0eb1b89 100644
--- a/src/test/fixtures/outputs/header-command-windows.conf
+++ b/src/test/fixtures/outputs/header-command-windows.conf
@@ -6,4 +6,11 @@ Host coder-jetbrains--header--test.coder.invalid
   UserKnownHostsFile /dev/null
   LogLevel ERROR
   SetEnv CODER_SSH_SESSION_TYPE=JetBrains
+Host coder-jetbrains--header--test.coder.invalid--bg
+  ProxyCommand CODER_SSH_USAGE_APP=disable /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config --header-command "\"C:\Program Files\My Header Command\HeaderCommand.exe\" --url=\"%%CODER_URL%%\" --test=\"foo bar\"" ssh --stdio header
+  ConnectTimeout 0
+  StrictHostKeyChecking no
+  UserKnownHostsFile /dev/null
+  LogLevel ERROR
+  SetEnv CODER_SSH_SESSION_TYPE=JetBrains
 # --- END CODER JETBRAINS test.coder.invalid
diff --git a/src/test/fixtures/outputs/header-command.conf b/src/test/fixtures/outputs/header-command.conf
index 04e422fb..ddb84b41 100644
--- a/src/test/fixtures/outputs/header-command.conf
+++ b/src/test/fixtures/outputs/header-command.conf
@@ -6,4 +6,11 @@ Host coder-jetbrains--header--test.coder.invalid
   UserKnownHostsFile /dev/null
   LogLevel ERROR
   SetEnv CODER_SSH_SESSION_TYPE=JetBrains
+Host coder-jetbrains--header--test.coder.invalid--bg
+  ProxyCommand CODER_SSH_USAGE_APP=disable /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config --header-command 'my-header-command --url="$CODER_URL" --test="foo bar" --literal='\''$CODER_URL'\''' ssh --stdio header
+  ConnectTimeout 0
+  StrictHostKeyChecking no
+  UserKnownHostsFile /dev/null
+  LogLevel ERROR
+  SetEnv CODER_SSH_SESSION_TYPE=JetBrains
 # --- END CODER JETBRAINS test.coder.invalid
diff --git a/src/test/fixtures/outputs/multiple-workspaces.conf b/src/test/fixtures/outputs/multiple-workspaces.conf
index 8cb3d81b..9ba2a089 100644
--- a/src/test/fixtures/outputs/multiple-workspaces.conf
+++ b/src/test/fixtures/outputs/multiple-workspaces.conf
@@ -6,6 +6,13 @@ Host coder-jetbrains--foo--test.coder.invalid
   UserKnownHostsFile /dev/null
   LogLevel ERROR
   SetEnv CODER_SSH_SESSION_TYPE=JetBrains
+Host coder-jetbrains--foo--test.coder.invalid--bg
+  ProxyCommand CODER_SSH_USAGE_APP=disable /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio foo
+  ConnectTimeout 0
+  StrictHostKeyChecking no
+  UserKnownHostsFile /dev/null
+  LogLevel ERROR
+  SetEnv CODER_SSH_SESSION_TYPE=JetBrains
 Host coder-jetbrains--bar--test.coder.invalid
   ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio bar
   ConnectTimeout 0
@@ -13,4 +20,11 @@ Host coder-jetbrains--bar--test.coder.invalid
   UserKnownHostsFile /dev/null
   LogLevel ERROR
   SetEnv CODER_SSH_SESSION_TYPE=JetBrains
+Host coder-jetbrains--bar--test.coder.invalid--bg
+  ProxyCommand CODER_SSH_USAGE_APP=disable /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio bar
+  ConnectTimeout 0
+  StrictHostKeyChecking no
+  UserKnownHostsFile /dev/null
+  LogLevel ERROR
+  SetEnv CODER_SSH_SESSION_TYPE=JetBrains
 # --- END CODER JETBRAINS test.coder.invalid
diff --git a/src/test/fixtures/outputs/no-disable-autostart.conf b/src/test/fixtures/outputs/no-disable-autostart.conf
index 217d332d..bc73c5b5 100644
--- a/src/test/fixtures/outputs/no-disable-autostart.conf
+++ b/src/test/fixtures/outputs/no-disable-autostart.conf
@@ -6,4 +6,11 @@ Host coder-jetbrains--foo--test.coder.invalid
   UserKnownHostsFile /dev/null
   LogLevel ERROR
   SetEnv CODER_SSH_SESSION_TYPE=JetBrains
+Host coder-jetbrains--foo--test.coder.invalid--bg
+  ProxyCommand CODER_SSH_USAGE_APP=disable /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio foo
+  ConnectTimeout 0
+  StrictHostKeyChecking no
+  UserKnownHostsFile /dev/null
+  LogLevel ERROR
+  SetEnv CODER_SSH_SESSION_TYPE=JetBrains
 # --- END CODER JETBRAINS test.coder.invalid
diff --git a/src/test/fixtures/outputs/replace-end-no-newline.conf b/src/test/fixtures/outputs/replace-end-no-newline.conf
index a2977f21..44c7efa0 100644
--- a/src/test/fixtures/outputs/replace-end-no-newline.conf
+++ b/src/test/fixtures/outputs/replace-end-no-newline.conf
@@ -9,4 +9,11 @@ Host coder-jetbrains--foo-bar--test.coder.invalid
   UserKnownHostsFile /dev/null
   LogLevel ERROR
   SetEnv CODER_SSH_SESSION_TYPE=JetBrains
+Host coder-jetbrains--foo-bar--test.coder.invalid--bg
+  ProxyCommand CODER_SSH_USAGE_APP=disable /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio foo-bar
+  ConnectTimeout 0
+  StrictHostKeyChecking no
+  UserKnownHostsFile /dev/null
+  LogLevel ERROR
+  SetEnv CODER_SSH_SESSION_TYPE=JetBrains
 # --- END CODER JETBRAINS test.coder.invalid
diff --git a/src/test/fixtures/outputs/replace-end.conf b/src/test/fixtures/outputs/replace-end.conf
index 3dad453d..fe46f597 100644
--- a/src/test/fixtures/outputs/replace-end.conf
+++ b/src/test/fixtures/outputs/replace-end.conf
@@ -10,4 +10,11 @@ Host coder-jetbrains--foo-bar--test.coder.invalid
   UserKnownHostsFile /dev/null
   LogLevel ERROR
   SetEnv CODER_SSH_SESSION_TYPE=JetBrains
+Host coder-jetbrains--foo-bar--test.coder.invalid--bg
+  ProxyCommand CODER_SSH_USAGE_APP=disable /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio foo-bar
+  ConnectTimeout 0
+  StrictHostKeyChecking no
+  UserKnownHostsFile /dev/null
+  LogLevel ERROR
+  SetEnv CODER_SSH_SESSION_TYPE=JetBrains
 # --- END CODER JETBRAINS test.coder.invalid
diff --git a/src/test/fixtures/outputs/replace-middle-ignore-unrelated.conf b/src/test/fixtures/outputs/replace-middle-ignore-unrelated.conf
index 37f73c47..f75c682f 100644
--- a/src/test/fixtures/outputs/replace-middle-ignore-unrelated.conf
+++ b/src/test/fixtures/outputs/replace-middle-ignore-unrelated.conf
@@ -11,6 +11,13 @@ Host coder-jetbrains--foo-bar--test.coder.invalid
   UserKnownHostsFile /dev/null
   LogLevel ERROR
   SetEnv CODER_SSH_SESSION_TYPE=JetBrains
+Host coder-jetbrains--foo-bar--test.coder.invalid--bg
+  ProxyCommand CODER_SSH_USAGE_APP=disable /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio foo-bar
+  ConnectTimeout 0
+  StrictHostKeyChecking no
+  UserKnownHostsFile /dev/null
+  LogLevel ERROR
+  SetEnv CODER_SSH_SESSION_TYPE=JetBrains
 # --- END CODER JETBRAINS test.coder.invalid
 Host test2
   Port 443
diff --git a/src/test/fixtures/outputs/replace-middle.conf b/src/test/fixtures/outputs/replace-middle.conf
index 7677238c..8010f19d 100644
--- a/src/test/fixtures/outputs/replace-middle.conf
+++ b/src/test/fixtures/outputs/replace-middle.conf
@@ -8,6 +8,13 @@ Host coder-jetbrains--foo-bar--test.coder.invalid
   UserKnownHostsFile /dev/null
   LogLevel ERROR
   SetEnv CODER_SSH_SESSION_TYPE=JetBrains
+Host coder-jetbrains--foo-bar--test.coder.invalid--bg
+  ProxyCommand CODER_SSH_USAGE_APP=disable /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio foo-bar
+  ConnectTimeout 0
+  StrictHostKeyChecking no
+  UserKnownHostsFile /dev/null
+  LogLevel ERROR
+  SetEnv CODER_SSH_SESSION_TYPE=JetBrains
 # --- END CODER JETBRAINS test.coder.invalid
 Host test2
   Port 443
diff --git a/src/test/fixtures/outputs/replace-only.conf b/src/test/fixtures/outputs/replace-only.conf
index 566a8522..d2b4ec3c 100644
--- a/src/test/fixtures/outputs/replace-only.conf
+++ b/src/test/fixtures/outputs/replace-only.conf
@@ -6,4 +6,11 @@ Host coder-jetbrains--foo-bar--test.coder.invalid
   UserKnownHostsFile /dev/null
   LogLevel ERROR
   SetEnv CODER_SSH_SESSION_TYPE=JetBrains
+Host coder-jetbrains--foo-bar--test.coder.invalid--bg
+  ProxyCommand CODER_SSH_USAGE_APP=disable /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio foo-bar
+  ConnectTimeout 0
+  StrictHostKeyChecking no
+  UserKnownHostsFile /dev/null
+  LogLevel ERROR
+  SetEnv CODER_SSH_SESSION_TYPE=JetBrains
 # --- END CODER JETBRAINS test.coder.invalid
diff --git a/src/test/fixtures/outputs/replace-start.conf b/src/test/fixtures/outputs/replace-start.conf
index 04cbe274..143b0b83 100644
--- a/src/test/fixtures/outputs/replace-start.conf
+++ b/src/test/fixtures/outputs/replace-start.conf
@@ -6,6 +6,13 @@ Host coder-jetbrains--foo-bar--test.coder.invalid
   UserKnownHostsFile /dev/null
   LogLevel ERROR
   SetEnv CODER_SSH_SESSION_TYPE=JetBrains
+Host coder-jetbrains--foo-bar--test.coder.invalid--bg
+  ProxyCommand CODER_SSH_USAGE_APP=disable /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio foo-bar
+  ConnectTimeout 0
+  StrictHostKeyChecking no
+  UserKnownHostsFile /dev/null
+  LogLevel ERROR
+  SetEnv CODER_SSH_SESSION_TYPE=JetBrains
 # --- END CODER JETBRAINS test.coder.invalid
 Host test
   Port 80

From 3ee1a2277679a09e45b3c7505d663ca7269d0d17 Mon Sep 17 00:00:00 2001
From: Garrett Delfosse <garrett@coder.com>
Date: Mon, 24 Jun 2024 21:14:09 +0000
Subject: [PATCH 02/10] remove space

---
 src/main/kotlin/com/coder/gateway/cli/CoderCLIManager.kt | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/main/kotlin/com/coder/gateway/cli/CoderCLIManager.kt b/src/main/kotlin/com/coder/gateway/cli/CoderCLIManager.kt
index 033f20b0..99f8781a 100644
--- a/src/main/kotlin/com/coder/gateway/cli/CoderCLIManager.kt
+++ b/src/main/kotlin/com/coder/gateway/cli/CoderCLIManager.kt
@@ -287,7 +287,6 @@ class CoderCLIManager(
                       UserKnownHostsFile /dev/null
                       LogLevel ERROR
                       SetEnv CODER_SSH_SESSION_TYPE=JetBrains
-
                     Host ${getBackgroundHostName(deploymentURL, it)}
                       ProxyCommand CODER_SSH_USAGE_APP=disable ${proxyArgs.joinToString(" ")} $it
                       ConnectTimeout 0

From 4155b136222237817847d010aa9623b08be98344 Mon Sep 17 00:00:00 2001
From: Garrett Delfosse <garrett@coder.com>
Date: Mon, 24 Jun 2024 21:23:40 +0000
Subject: [PATCH 03/10] try test fix

---
 .../com/coder/gateway/cli/CoderCLIManager.kt  | 19 ++++++++++++-------
 1 file changed, 12 insertions(+), 7 deletions(-)

diff --git a/src/main/kotlin/com/coder/gateway/cli/CoderCLIManager.kt b/src/main/kotlin/com/coder/gateway/cli/CoderCLIManager.kt
index 99f8781a..3557cccb 100644
--- a/src/main/kotlin/com/coder/gateway/cli/CoderCLIManager.kt
+++ b/src/main/kotlin/com/coder/gateway/cli/CoderCLIManager.kt
@@ -287,15 +287,20 @@ class CoderCLIManager(
                       UserKnownHostsFile /dev/null
                       LogLevel ERROR
                       SetEnv CODER_SSH_SESSION_TYPE=JetBrains
-                    Host ${getBackgroundHostName(deploymentURL, it)}
-                      ProxyCommand CODER_SSH_USAGE_APP=disable ${proxyArgs.joinToString(" ")} $it
-                      ConnectTimeout 0
-                      StrictHostKeyChecking no
-                      UserKnownHostsFile /dev/null
-                      LogLevel ERROR
-                      SetEnv CODER_SSH_SESSION_TYPE=JetBrains
                     """.trimIndent()
                         .plus(extraConfig)
+                        .plus(
+                        """
+                        Host ${getBackgroundHostName(deploymentURL, it)}
+                            ProxyCommand CODER_SSH_USAGE_APP=disable ${proxyArgs.joinToString(" ")} $it
+                            ConnectTimeout 0
+                            StrictHostKeyChecking no
+                            UserKnownHostsFile /dev/null
+                            LogLevel ERROR
+                            SetEnv CODER_SSH_SESSION_TYPE=JetBrains
+                        """.trimIndent()
+                            .plus(extraConfig)
+                        )
                         .replace("\n", System.lineSeparator())
                 },
             )

From 44856b457d06a0f267c809c02514cb0f8b6748ad Mon Sep 17 00:00:00 2001
From: Garrett Delfosse <garrett@coder.com>
Date: Mon, 24 Jun 2024 21:29:40 +0000
Subject: [PATCH 04/10] try test fix

---
 .../com/coder/gateway/cli/CoderCLIManager.kt  | 21 ++++++++++---------
 1 file changed, 11 insertions(+), 10 deletions(-)

diff --git a/src/main/kotlin/com/coder/gateway/cli/CoderCLIManager.kt b/src/main/kotlin/com/coder/gateway/cli/CoderCLIManager.kt
index 3557cccb..d6f10a35 100644
--- a/src/main/kotlin/com/coder/gateway/cli/CoderCLIManager.kt
+++ b/src/main/kotlin/com/coder/gateway/cli/CoderCLIManager.kt
@@ -289,18 +289,19 @@ class CoderCLIManager(
                       SetEnv CODER_SSH_SESSION_TYPE=JetBrains
                     """.trimIndent()
                         .plus(extraConfig)
+                        .plus(System.lineSeparator())
                         .plus(
-                        """
-                        Host ${getBackgroundHostName(deploymentURL, it)}
-                            ProxyCommand CODER_SSH_USAGE_APP=disable ${proxyArgs.joinToString(" ")} $it
-                            ConnectTimeout 0
-                            StrictHostKeyChecking no
-                            UserKnownHostsFile /dev/null
-                            LogLevel ERROR
-                            SetEnv CODER_SSH_SESSION_TYPE=JetBrains
-                        """.trimIndent()
-                            .plus(extraConfig)
+                            """
+                            Host ${getBackgroundHostName(deploymentURL, it)}
+                              ProxyCommand CODER_SSH_USAGE_APP=disable ${proxyArgs.joinToString(" ")} $it
+                              ConnectTimeout 0
+                              StrictHostKeyChecking no
+                              UserKnownHostsFile /dev/null
+                              LogLevel ERROR
+                              SetEnv CODER_SSH_SESSION_TYPE=JetBrains
+                            """.trimIndent()
                         )
+                        .plus(extraConfig)
                         .replace("\n", System.lineSeparator())
                 },
             )

From 405a4857972d778321f57cb57df7921fa0bf08aa Mon Sep 17 00:00:00 2001
From: Garrett Delfosse <garrett@coder.com>
Date: Mon, 24 Jun 2024 21:37:27 +0000
Subject: [PATCH 05/10] try test fix

---
 src/main/kotlin/com/coder/gateway/cli/CoderCLIManager.kt | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/src/main/kotlin/com/coder/gateway/cli/CoderCLIManager.kt b/src/main/kotlin/com/coder/gateway/cli/CoderCLIManager.kt
index d6f10a35..5993bff3 100644
--- a/src/main/kotlin/com/coder/gateway/cli/CoderCLIManager.kt
+++ b/src/main/kotlin/com/coder/gateway/cli/CoderCLIManager.kt
@@ -289,7 +289,6 @@ class CoderCLIManager(
                       SetEnv CODER_SSH_SESSION_TYPE=JetBrains
                     """.trimIndent()
                         .plus(extraConfig)
-                        .plus(System.lineSeparator())
                         .plus(
                             """
                             Host ${getBackgroundHostName(deploymentURL, it)}
@@ -300,8 +299,8 @@ class CoderCLIManager(
                               LogLevel ERROR
                               SetEnv CODER_SSH_SESSION_TYPE=JetBrains
                             """.trimIndent()
+                                .plus(extraConfig)
                         )
-                        .plus(extraConfig)
                         .replace("\n", System.lineSeparator())
                 },
             )

From 75c825dd6290137f06b815e8ca5a2b5268f4596d Mon Sep 17 00:00:00 2001
From: Garrett Delfosse <garrett@coder.com>
Date: Tue, 25 Jun 2024 18:21:14 +0000
Subject: [PATCH 06/10] rebase

---
 .../gateway/CoderRemoteConnectionHandle.kt    |  3 +-
 .../com/coder/gateway/cli/CoderCLIManager.kt  |  9 ++++-
 .../outputs/append-blank-newlines.conf        |  4 +--
 src/test/fixtures/outputs/append-blank.conf   |  4 +--
 .../fixtures/outputs/append-no-blocks.conf    |  4 +--
 .../fixtures/outputs/append-no-newline.conf   |  4 +--
 .../outputs/append-no-related-blocks.conf     |  4 +--
 .../fixtures/outputs/disable-autostart.conf   |  4 +--
 src/test/fixtures/outputs/extra-config.conf   |  4 +--
 .../outputs/header-command-windows.conf       |  4 +--
 src/test/fixtures/outputs/header-command.conf |  4 +--
 .../fixtures/outputs/multiple-workspaces.conf |  8 ++---
 .../outputs/no-disable-autostart.conf         |  4 +--
 ...report-usage.conf => no-report-usage.conf} |  9 ++++-
 .../outputs/replace-end-no-newline.conf       |  4 +--
 src/test/fixtures/outputs/replace-end.conf    |  4 +--
 .../replace-middle-ignore-unrelated.conf      |  4 +--
 src/test/fixtures/outputs/replace-middle.conf |  4 +--
 src/test/fixtures/outputs/replace-only.conf   |  4 +--
 src/test/fixtures/outputs/replace-start.conf  |  4 +--
 .../coder/gateway/cli/CoderCLIManagerTest.kt  | 36 ++++++++++---------
 21 files changed, 74 insertions(+), 55 deletions(-)
 rename src/test/fixtures/outputs/{report-usage.conf => no-report-usage.conf} (53%)

diff --git a/src/main/kotlin/com/coder/gateway/CoderRemoteConnectionHandle.kt b/src/main/kotlin/com/coder/gateway/CoderRemoteConnectionHandle.kt
index 5d610107..f4e86850 100644
--- a/src/main/kotlin/com/coder/gateway/CoderRemoteConnectionHandle.kt
+++ b/src/main/kotlin/com/coder/gateway/CoderRemoteConnectionHandle.kt
@@ -10,6 +10,7 @@ import com.coder.gateway.util.humanizeDuration
 import com.coder.gateway.util.isCancellation
 import com.coder.gateway.util.isWorkerTimeout
 import com.coder.gateway.util.suspendingRetryWithExponentialBackOff
+import com.coder.gateway.cli.CoderCLIManager
 import com.intellij.openapi.application.ApplicationManager
 import com.intellij.openapi.components.service
 import com.intellij.openapi.diagnostic.Logger
@@ -142,7 +143,7 @@ class CoderRemoteConnectionHandle {
             authType = AuthType.OPEN_SSH
         }
         val backgroundCredentials = RemoteCredentialsHolder().apply {
-            setHost(workspace.hostname)
+            setHost(CoderCLIManager.getBackgroundHostName(workspace.hostname))
             userName = "coder"
             port = 22
             authType = AuthType.OPEN_SSH
diff --git a/src/main/kotlin/com/coder/gateway/cli/CoderCLIManager.kt b/src/main/kotlin/com/coder/gateway/cli/CoderCLIManager.kt
index 5993bff3..f64cec07 100644
--- a/src/main/kotlin/com/coder/gateway/cli/CoderCLIManager.kt
+++ b/src/main/kotlin/com/coder/gateway/cli/CoderCLIManager.kt
@@ -292,7 +292,7 @@ class CoderCLIManager(
                         .plus(
                             """
                             Host ${getBackgroundHostName(deploymentURL, it)}
-                              ProxyCommand CODER_SSH_USAGE_APP=disable ${proxyArgs.joinToString(" ")} $it
+                              ProxyCommand ${proxyArgs.joinToString(" ")} $it
                               ConnectTimeout 0
                               StrictHostKeyChecking no
                               UserKnownHostsFile /dev/null
@@ -485,5 +485,12 @@ class CoderCLIManager(
         ): String {
             return getHostName(url, workspaceName) + "--bg"
         }
+
+        @JvmStatic
+        fun getBackgroundHostName(
+            hostname: String,
+        ): String {
+            return hostname + "--bg"
+        }
     }
 }
diff --git a/src/test/fixtures/outputs/append-blank-newlines.conf b/src/test/fixtures/outputs/append-blank-newlines.conf
index 6a3ae5d3..022b30b7 100644
--- a/src/test/fixtures/outputs/append-blank-newlines.conf
+++ b/src/test/fixtures/outputs/append-blank-newlines.conf
@@ -4,14 +4,14 @@
 
 # --- START CODER JETBRAINS test.coder.invalid
 Host coder-jetbrains--foo-bar--test.coder.invalid
-  ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio foo-bar
+  ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio --usage-app=jetbrains foo-bar
   ConnectTimeout 0
   StrictHostKeyChecking no
   UserKnownHostsFile /dev/null
   LogLevel ERROR
   SetEnv CODER_SSH_SESSION_TYPE=JetBrains
 Host coder-jetbrains--foo-bar--test.coder.invalid--bg
-  ProxyCommand CODER_SSH_USAGE_APP=disable /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio foo-bar
+  ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio --usage-app=disable foo-bar
   ConnectTimeout 0
   StrictHostKeyChecking no
   UserKnownHostsFile /dev/null
diff --git a/src/test/fixtures/outputs/append-blank.conf b/src/test/fixtures/outputs/append-blank.conf
index d2b4ec3c..d04a5c6c 100644
--- a/src/test/fixtures/outputs/append-blank.conf
+++ b/src/test/fixtures/outputs/append-blank.conf
@@ -1,13 +1,13 @@
 # --- START CODER JETBRAINS test.coder.invalid
 Host coder-jetbrains--foo-bar--test.coder.invalid
-  ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio foo-bar
+  ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio --usage-app=jetbrains foo-bar
   ConnectTimeout 0
   StrictHostKeyChecking no
   UserKnownHostsFile /dev/null
   LogLevel ERROR
   SetEnv CODER_SSH_SESSION_TYPE=JetBrains
 Host coder-jetbrains--foo-bar--test.coder.invalid--bg
-  ProxyCommand CODER_SSH_USAGE_APP=disable /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio foo-bar
+  ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio --usage-app=disable foo-bar
   ConnectTimeout 0
   StrictHostKeyChecking no
   UserKnownHostsFile /dev/null
diff --git a/src/test/fixtures/outputs/append-no-blocks.conf b/src/test/fixtures/outputs/append-no-blocks.conf
index 25a33376..187bd2c8 100644
--- a/src/test/fixtures/outputs/append-no-blocks.conf
+++ b/src/test/fixtures/outputs/append-no-blocks.conf
@@ -5,14 +5,14 @@ Host test2
 
 # --- START CODER JETBRAINS test.coder.invalid
 Host coder-jetbrains--foo-bar--test.coder.invalid
-  ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio foo-bar
+  ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio --usage-app=jetbrains foo-bar
   ConnectTimeout 0
   StrictHostKeyChecking no
   UserKnownHostsFile /dev/null
   LogLevel ERROR
   SetEnv CODER_SSH_SESSION_TYPE=JetBrains
 Host coder-jetbrains--foo-bar--test.coder.invalid--bg
-  ProxyCommand CODER_SSH_USAGE_APP=disable /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio foo-bar
+  ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio --usage-app=disable foo-bar
   ConnectTimeout 0
   StrictHostKeyChecking no
   UserKnownHostsFile /dev/null
diff --git a/src/test/fixtures/outputs/append-no-newline.conf b/src/test/fixtures/outputs/append-no-newline.conf
index fe46f597..d7e52efa 100644
--- a/src/test/fixtures/outputs/append-no-newline.conf
+++ b/src/test/fixtures/outputs/append-no-newline.conf
@@ -4,14 +4,14 @@ Host test2
   Port 443
 # --- START CODER JETBRAINS test.coder.invalid
 Host coder-jetbrains--foo-bar--test.coder.invalid
-  ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio foo-bar
+  ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio --usage-app=jetbrains foo-bar
   ConnectTimeout 0
   StrictHostKeyChecking no
   UserKnownHostsFile /dev/null
   LogLevel ERROR
   SetEnv CODER_SSH_SESSION_TYPE=JetBrains
 Host coder-jetbrains--foo-bar--test.coder.invalid--bg
-  ProxyCommand CODER_SSH_USAGE_APP=disable /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio foo-bar
+  ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio --usage-app=disable foo-bar
   ConnectTimeout 0
   StrictHostKeyChecking no
   UserKnownHostsFile /dev/null
diff --git a/src/test/fixtures/outputs/append-no-related-blocks.conf b/src/test/fixtures/outputs/append-no-related-blocks.conf
index 86c8d934..b90a9221 100644
--- a/src/test/fixtures/outputs/append-no-related-blocks.conf
+++ b/src/test/fixtures/outputs/append-no-related-blocks.conf
@@ -11,14 +11,14 @@ some jetbrains config
 
 # --- START CODER JETBRAINS test.coder.invalid
 Host coder-jetbrains--foo-bar--test.coder.invalid
-  ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio foo-bar
+  ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio --usage-app=jetbrains foo-bar
   ConnectTimeout 0
   StrictHostKeyChecking no
   UserKnownHostsFile /dev/null
   LogLevel ERROR
   SetEnv CODER_SSH_SESSION_TYPE=JetBrains
 Host coder-jetbrains--foo-bar--test.coder.invalid--bg
-  ProxyCommand CODER_SSH_USAGE_APP=disable /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio foo-bar
+  ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio --usage-app=disable foo-bar
   ConnectTimeout 0
   StrictHostKeyChecking no
   UserKnownHostsFile /dev/null
diff --git a/src/test/fixtures/outputs/disable-autostart.conf b/src/test/fixtures/outputs/disable-autostart.conf
index 280b97d4..9bce080b 100644
--- a/src/test/fixtures/outputs/disable-autostart.conf
+++ b/src/test/fixtures/outputs/disable-autostart.conf
@@ -1,13 +1,13 @@
 # --- START CODER JETBRAINS test.coder.invalid
 Host coder-jetbrains--foo--test.coder.invalid
-  ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio --disable-autostart foo
+  ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio --disable-autostart --usage-app=jetbrains foo
   ConnectTimeout 0
   StrictHostKeyChecking no
   UserKnownHostsFile /dev/null
   LogLevel ERROR
   SetEnv CODER_SSH_SESSION_TYPE=JetBrains
 Host coder-jetbrains--foo--test.coder.invalid--bg
-  ProxyCommand CODER_SSH_USAGE_APP=disable /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio --disable-autostart foo
+  ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio --disable-autostart --usage-app=disable foo
   ConnectTimeout 0
   StrictHostKeyChecking no
   UserKnownHostsFile /dev/null
diff --git a/src/test/fixtures/outputs/extra-config.conf b/src/test/fixtures/outputs/extra-config.conf
index 2fff157d..3186b8d7 100644
--- a/src/test/fixtures/outputs/extra-config.conf
+++ b/src/test/fixtures/outputs/extra-config.conf
@@ -1,6 +1,6 @@
 # --- START CODER JETBRAINS test.coder.invalid
 Host coder-jetbrains--extra--test.coder.invalid
-  ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio extra
+  ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio --usage-app=jetbrains extra
   ConnectTimeout 0
   StrictHostKeyChecking no
   UserKnownHostsFile /dev/null
@@ -9,7 +9,7 @@ Host coder-jetbrains--extra--test.coder.invalid
   ServerAliveInterval 5
   ServerAliveCountMax 3
 Host coder-jetbrains--extra--test.coder.invalid--bg
-  ProxyCommand CODER_SSH_USAGE_APP=disable /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio extra
+  ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio --usage-app=disable extra
   ConnectTimeout 0
   StrictHostKeyChecking no
   UserKnownHostsFile /dev/null
diff --git a/src/test/fixtures/outputs/header-command-windows.conf b/src/test/fixtures/outputs/header-command-windows.conf
index a0eb1b89..d14340e4 100644
--- a/src/test/fixtures/outputs/header-command-windows.conf
+++ b/src/test/fixtures/outputs/header-command-windows.conf
@@ -1,13 +1,13 @@
 # --- START CODER JETBRAINS test.coder.invalid
 Host coder-jetbrains--header--test.coder.invalid
-  ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config --header-command "\"C:\Program Files\My Header Command\HeaderCommand.exe\" --url=\"%%CODER_URL%%\" --test=\"foo bar\"" ssh --stdio header
+  ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config --header-command "\"C:\Program Files\My Header Command\HeaderCommand.exe\" --url=\"%%CODER_URL%%\" --test=\"foo bar\"" ssh --stdio --usage-app=jetbrains header
   ConnectTimeout 0
   StrictHostKeyChecking no
   UserKnownHostsFile /dev/null
   LogLevel ERROR
   SetEnv CODER_SSH_SESSION_TYPE=JetBrains
 Host coder-jetbrains--header--test.coder.invalid--bg
-  ProxyCommand CODER_SSH_USAGE_APP=disable /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config --header-command "\"C:\Program Files\My Header Command\HeaderCommand.exe\" --url=\"%%CODER_URL%%\" --test=\"foo bar\"" ssh --stdio header
+  ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config --header-command "\"C:\Program Files\My Header Command\HeaderCommand.exe\" --url=\"%%CODER_URL%%\" --test=\"foo bar\"" ssh --stdio --usage-app=disable header
   ConnectTimeout 0
   StrictHostKeyChecking no
   UserKnownHostsFile /dev/null
diff --git a/src/test/fixtures/outputs/header-command.conf b/src/test/fixtures/outputs/header-command.conf
index ddb84b41..b82f4cf0 100644
--- a/src/test/fixtures/outputs/header-command.conf
+++ b/src/test/fixtures/outputs/header-command.conf
@@ -1,13 +1,13 @@
 # --- START CODER JETBRAINS test.coder.invalid
 Host coder-jetbrains--header--test.coder.invalid
-  ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config --header-command 'my-header-command --url="$CODER_URL" --test="foo bar" --literal='\''$CODER_URL'\''' ssh --stdio header
+  ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config --header-command 'my-header-command --url="$CODER_URL" --test="foo bar" --literal='\''$CODER_URL'\''' ssh --stdio --usage-app=jetbrains header
   ConnectTimeout 0
   StrictHostKeyChecking no
   UserKnownHostsFile /dev/null
   LogLevel ERROR
   SetEnv CODER_SSH_SESSION_TYPE=JetBrains
 Host coder-jetbrains--header--test.coder.invalid--bg
-  ProxyCommand CODER_SSH_USAGE_APP=disable /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config --header-command 'my-header-command --url="$CODER_URL" --test="foo bar" --literal='\''$CODER_URL'\''' ssh --stdio header
+  ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config --header-command 'my-header-command --url="$CODER_URL" --test="foo bar" --literal='\''$CODER_URL'\''' ssh --stdio --usage-app=disable header
   ConnectTimeout 0
   StrictHostKeyChecking no
   UserKnownHostsFile /dev/null
diff --git a/src/test/fixtures/outputs/multiple-workspaces.conf b/src/test/fixtures/outputs/multiple-workspaces.conf
index 9ba2a089..c6c733e1 100644
--- a/src/test/fixtures/outputs/multiple-workspaces.conf
+++ b/src/test/fixtures/outputs/multiple-workspaces.conf
@@ -1,27 +1,27 @@
 # --- START CODER JETBRAINS test.coder.invalid
 Host coder-jetbrains--foo--test.coder.invalid
-  ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio foo
+  ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio --usage-app=jetbrains foo
   ConnectTimeout 0
   StrictHostKeyChecking no
   UserKnownHostsFile /dev/null
   LogLevel ERROR
   SetEnv CODER_SSH_SESSION_TYPE=JetBrains
 Host coder-jetbrains--foo--test.coder.invalid--bg
-  ProxyCommand CODER_SSH_USAGE_APP=disable /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio foo
+  ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio --usage-app=disable foo
   ConnectTimeout 0
   StrictHostKeyChecking no
   UserKnownHostsFile /dev/null
   LogLevel ERROR
   SetEnv CODER_SSH_SESSION_TYPE=JetBrains
 Host coder-jetbrains--bar--test.coder.invalid
-  ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio bar
+  ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio --usage-app=jetbrains bar
   ConnectTimeout 0
   StrictHostKeyChecking no
   UserKnownHostsFile /dev/null
   LogLevel ERROR
   SetEnv CODER_SSH_SESSION_TYPE=JetBrains
 Host coder-jetbrains--bar--test.coder.invalid--bg
-  ProxyCommand CODER_SSH_USAGE_APP=disable /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio bar
+  ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio --usage-app=disable bar
   ConnectTimeout 0
   StrictHostKeyChecking no
   UserKnownHostsFile /dev/null
diff --git a/src/test/fixtures/outputs/no-disable-autostart.conf b/src/test/fixtures/outputs/no-disable-autostart.conf
index bc73c5b5..5665634d 100644
--- a/src/test/fixtures/outputs/no-disable-autostart.conf
+++ b/src/test/fixtures/outputs/no-disable-autostart.conf
@@ -1,13 +1,13 @@
 # --- START CODER JETBRAINS test.coder.invalid
 Host coder-jetbrains--foo--test.coder.invalid
-  ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio foo
+  ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio --usage-app=jetbrains foo
   ConnectTimeout 0
   StrictHostKeyChecking no
   UserKnownHostsFile /dev/null
   LogLevel ERROR
   SetEnv CODER_SSH_SESSION_TYPE=JetBrains
 Host coder-jetbrains--foo--test.coder.invalid--bg
-  ProxyCommand CODER_SSH_USAGE_APP=disable /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio foo
+  ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio --usage-app=disable foo
   ConnectTimeout 0
   StrictHostKeyChecking no
   UserKnownHostsFile /dev/null
diff --git a/src/test/fixtures/outputs/report-usage.conf b/src/test/fixtures/outputs/no-report-usage.conf
similarity index 53%
rename from src/test/fixtures/outputs/report-usage.conf
rename to src/test/fixtures/outputs/no-report-usage.conf
index 635e48ef..27e2ecf1 100644
--- a/src/test/fixtures/outputs/report-usage.conf
+++ b/src/test/fixtures/outputs/no-report-usage.conf
@@ -1,6 +1,13 @@
 # --- START CODER JETBRAINS test.coder.invalid
 Host coder-jetbrains--foo--test.coder.invalid
-  ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio --usage-app=jetbrains foo
+  ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio foo
+  ConnectTimeout 0
+  StrictHostKeyChecking no
+  UserKnownHostsFile /dev/null
+  LogLevel ERROR
+  SetEnv CODER_SSH_SESSION_TYPE=JetBrains
+Host coder-jetbrains--foo--test.coder.invalid--bg
+  ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio foo
   ConnectTimeout 0
   StrictHostKeyChecking no
   UserKnownHostsFile /dev/null
diff --git a/src/test/fixtures/outputs/replace-end-no-newline.conf b/src/test/fixtures/outputs/replace-end-no-newline.conf
index 44c7efa0..e6a43a9d 100644
--- a/src/test/fixtures/outputs/replace-end-no-newline.conf
+++ b/src/test/fixtures/outputs/replace-end-no-newline.conf
@@ -3,14 +3,14 @@ Host test
 Host test2
   Port 443 # --- START CODER JETBRAINS test.coder.invalid
 Host coder-jetbrains--foo-bar--test.coder.invalid
-  ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio foo-bar
+  ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio --usage-app=jetbrains foo-bar
   ConnectTimeout 0
   StrictHostKeyChecking no
   UserKnownHostsFile /dev/null
   LogLevel ERROR
   SetEnv CODER_SSH_SESSION_TYPE=JetBrains
 Host coder-jetbrains--foo-bar--test.coder.invalid--bg
-  ProxyCommand CODER_SSH_USAGE_APP=disable /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio foo-bar
+  ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio --usage-app=disable foo-bar
   ConnectTimeout 0
   StrictHostKeyChecking no
   UserKnownHostsFile /dev/null
diff --git a/src/test/fixtures/outputs/replace-end.conf b/src/test/fixtures/outputs/replace-end.conf
index fe46f597..d7e52efa 100644
--- a/src/test/fixtures/outputs/replace-end.conf
+++ b/src/test/fixtures/outputs/replace-end.conf
@@ -4,14 +4,14 @@ Host test2
   Port 443
 # --- START CODER JETBRAINS test.coder.invalid
 Host coder-jetbrains--foo-bar--test.coder.invalid
-  ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio foo-bar
+  ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio --usage-app=jetbrains foo-bar
   ConnectTimeout 0
   StrictHostKeyChecking no
   UserKnownHostsFile /dev/null
   LogLevel ERROR
   SetEnv CODER_SSH_SESSION_TYPE=JetBrains
 Host coder-jetbrains--foo-bar--test.coder.invalid--bg
-  ProxyCommand CODER_SSH_USAGE_APP=disable /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio foo-bar
+  ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio --usage-app=disable foo-bar
   ConnectTimeout 0
   StrictHostKeyChecking no
   UserKnownHostsFile /dev/null
diff --git a/src/test/fixtures/outputs/replace-middle-ignore-unrelated.conf b/src/test/fixtures/outputs/replace-middle-ignore-unrelated.conf
index f75c682f..156c95c7 100644
--- a/src/test/fixtures/outputs/replace-middle-ignore-unrelated.conf
+++ b/src/test/fixtures/outputs/replace-middle-ignore-unrelated.conf
@@ -5,14 +5,14 @@ some coder config
 # ------------END-CODER------------
 # --- START CODER JETBRAINS test.coder.invalid
 Host coder-jetbrains--foo-bar--test.coder.invalid
-  ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio foo-bar
+  ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio --usage-app=jetbrains foo-bar
   ConnectTimeout 0
   StrictHostKeyChecking no
   UserKnownHostsFile /dev/null
   LogLevel ERROR
   SetEnv CODER_SSH_SESSION_TYPE=JetBrains
 Host coder-jetbrains--foo-bar--test.coder.invalid--bg
-  ProxyCommand CODER_SSH_USAGE_APP=disable /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio foo-bar
+  ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio --usage-app=disable foo-bar
   ConnectTimeout 0
   StrictHostKeyChecking no
   UserKnownHostsFile /dev/null
diff --git a/src/test/fixtures/outputs/replace-middle.conf b/src/test/fixtures/outputs/replace-middle.conf
index 8010f19d..803e8823 100644
--- a/src/test/fixtures/outputs/replace-middle.conf
+++ b/src/test/fixtures/outputs/replace-middle.conf
@@ -2,14 +2,14 @@ Host test
   Port 80
 # --- START CODER JETBRAINS test.coder.invalid
 Host coder-jetbrains--foo-bar--test.coder.invalid
-  ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio foo-bar
+  ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio --usage-app=jetbrains foo-bar
   ConnectTimeout 0
   StrictHostKeyChecking no
   UserKnownHostsFile /dev/null
   LogLevel ERROR
   SetEnv CODER_SSH_SESSION_TYPE=JetBrains
 Host coder-jetbrains--foo-bar--test.coder.invalid--bg
-  ProxyCommand CODER_SSH_USAGE_APP=disable /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio foo-bar
+  ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio --usage-app=disable foo-bar
   ConnectTimeout 0
   StrictHostKeyChecking no
   UserKnownHostsFile /dev/null
diff --git a/src/test/fixtures/outputs/replace-only.conf b/src/test/fixtures/outputs/replace-only.conf
index d2b4ec3c..d04a5c6c 100644
--- a/src/test/fixtures/outputs/replace-only.conf
+++ b/src/test/fixtures/outputs/replace-only.conf
@@ -1,13 +1,13 @@
 # --- START CODER JETBRAINS test.coder.invalid
 Host coder-jetbrains--foo-bar--test.coder.invalid
-  ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio foo-bar
+  ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio --usage-app=jetbrains foo-bar
   ConnectTimeout 0
   StrictHostKeyChecking no
   UserKnownHostsFile /dev/null
   LogLevel ERROR
   SetEnv CODER_SSH_SESSION_TYPE=JetBrains
 Host coder-jetbrains--foo-bar--test.coder.invalid--bg
-  ProxyCommand CODER_SSH_USAGE_APP=disable /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio foo-bar
+  ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio --usage-app=disable foo-bar
   ConnectTimeout 0
   StrictHostKeyChecking no
   UserKnownHostsFile /dev/null
diff --git a/src/test/fixtures/outputs/replace-start.conf b/src/test/fixtures/outputs/replace-start.conf
index 143b0b83..d13ff038 100644
--- a/src/test/fixtures/outputs/replace-start.conf
+++ b/src/test/fixtures/outputs/replace-start.conf
@@ -1,13 +1,13 @@
 # --- START CODER JETBRAINS test.coder.invalid
 Host coder-jetbrains--foo-bar--test.coder.invalid
-  ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio foo-bar
+  ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio --usage-app=jetbrains foo-bar
   ConnectTimeout 0
   StrictHostKeyChecking no
   UserKnownHostsFile /dev/null
   LogLevel ERROR
   SetEnv CODER_SSH_SESSION_TYPE=JetBrains
 Host coder-jetbrains--foo-bar--test.coder.invalid--bg
-  ProxyCommand CODER_SSH_USAGE_APP=disable /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio foo-bar
+  ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio --usage-app=disable foo-bar
   ConnectTimeout 0
   StrictHostKeyChecking no
   UserKnownHostsFile /dev/null
diff --git a/src/test/kotlin/com/coder/gateway/cli/CoderCLIManagerTest.kt b/src/test/kotlin/com/coder/gateway/cli/CoderCLIManagerTest.kt
index 51a6339a..428f04da 100644
--- a/src/test/kotlin/com/coder/gateway/cli/CoderCLIManagerTest.kt
+++ b/src/test/kotlin/com/coder/gateway/cli/CoderCLIManagerTest.kt
@@ -313,19 +313,19 @@ internal class CoderCLIManagerTest {
             ).joinToString(System.lineSeparator())
         val tests =
             listOf(
-                SSHTest(listOf("foo", "bar"), null, "multiple-workspaces", "blank"),
-                SSHTest(listOf("foo", "bar"), null, "multiple-workspaces", "blank"),
-                SSHTest(listOf("foo-bar"), "blank", "append-blank", "blank"),
-                SSHTest(listOf("foo-bar"), "blank-newlines", "append-blank-newlines", "blank"),
-                SSHTest(listOf("foo-bar"), "existing-end", "replace-end", "no-blocks"),
-                SSHTest(listOf("foo-bar"), "existing-end-no-newline", "replace-end-no-newline", "no-blocks"),
-                SSHTest(listOf("foo-bar"), "existing-middle", "replace-middle", "no-blocks"),
-                SSHTest(listOf("foo-bar"), "existing-middle-and-unrelated", "replace-middle-ignore-unrelated", "no-related-blocks"),
-                SSHTest(listOf("foo-bar"), "existing-only", "replace-only", "blank"),
-                SSHTest(listOf("foo-bar"), "existing-start", "replace-start", "no-blocks"),
-                SSHTest(listOf("foo-bar"), "no-blocks", "append-no-blocks", "no-blocks"),
-                SSHTest(listOf("foo-bar"), "no-related-blocks", "append-no-related-blocks", "no-related-blocks"),
-                SSHTest(listOf("foo-bar"), "no-newline", "append-no-newline", "no-blocks"),
+                SSHTest(listOf("foo", "bar"), null, "multiple-workspaces", "blank", features = Features(false, true)),
+                SSHTest(listOf("foo", "bar"), null, "multiple-workspaces", "blank", features = Features(false, true)),
+                SSHTest(listOf("foo-bar"), "blank", "append-blank", "blank", features = Features(false, true)),
+                SSHTest(listOf("foo-bar"), "blank-newlines", "append-blank-newlines", "blank", features = Features(false, true)),
+                SSHTest(listOf("foo-bar"), "existing-end", "replace-end", "no-blocks", features = Features(false, true)),
+                SSHTest(listOf("foo-bar"), "existing-end-no-newline", "replace-end-no-newline", "no-blocks", features = Features(false, true)),
+                SSHTest(listOf("foo-bar"), "existing-middle", "replace-middle", "no-blocks", features = Features(false, true)),
+                SSHTest(listOf("foo-bar"), "existing-middle-and-unrelated", "replace-middle-ignore-unrelated", "no-related-blocks", features = Features(false, true)),
+                SSHTest(listOf("foo-bar"), "existing-only", "replace-only", "blank", features = Features(false, true)),
+                SSHTest(listOf("foo-bar"), "existing-start", "replace-start", "no-blocks", features = Features(false, true)),
+                SSHTest(listOf("foo-bar"), "no-blocks", "append-no-blocks", "no-blocks", features = Features(false, true)),
+                SSHTest(listOf("foo-bar"), "no-related-blocks", "append-no-related-blocks", "no-related-blocks", features = Features(false, true)),
+                SSHTest(listOf("foo-bar"), "no-newline", "append-no-newline", "no-blocks", features = Features(false, true)),
                 if (getOS() == OS.WINDOWS) {
                     SSHTest(
                         listOf("header"),
@@ -333,6 +333,7 @@ internal class CoderCLIManagerTest {
                         "header-command-windows",
                         "blank",
                         """"C:\Program Files\My Header Command\HeaderCommand.exe" --url="%CODER_URL%" --test="foo bar"""",
+                        features = Features(false, true)
                     )
                 } else {
                     SSHTest(
@@ -341,17 +342,19 @@ internal class CoderCLIManagerTest {
                         "header-command",
                         "blank",
                         "my-header-command --url=\"\$CODER_URL\" --test=\"foo bar\" --literal='\$CODER_URL'",
+                        features = Features(false, true)
                     )
                 },
-                SSHTest(listOf("foo"), null, "disable-autostart", "blank", "", true, Features(true)),
-                SSHTest(listOf("foo"), null, "no-disable-autostart", "blank", "", true, Features(false)),
-                SSHTest(listOf("foo"), null, "report-usage", "blank", "", true, Features(false, true)),
+                SSHTest(listOf("foo"), null, "disable-autostart", "blank", "", true, Features(true, true)),
+                SSHTest(listOf("foo"), null, "no-disable-autostart", "blank", "", true, Features(false, true)),
+                SSHTest(listOf("foo"), null, "no-report-usage", "blank", "", true, Features(false, false)),
                 SSHTest(
                     listOf("extra"),
                     null,
                     "extra-config",
                     "blank",
                     extraConfig = extraConfig,
+                    features = Features(false, true)
                 ),
                 SSHTest(
                     listOf("extra"),
@@ -359,6 +362,7 @@ internal class CoderCLIManagerTest {
                     "extra-config",
                     "blank",
                     env = Environment(mapOf(CODER_SSH_CONFIG_OPTIONS to extraConfig)),
+                    features = Features(false, true)
                 ),
             )
 

From 6ff068145433518313148ace6945c5d0458b474c Mon Sep 17 00:00:00 2001
From: Garrett Delfosse <garrett@coder.com>
Date: Tue, 25 Jun 2024 18:31:24 +0000
Subject: [PATCH 07/10] use background on ssh command exec

---
 .../kotlin/com/coder/gateway/CoderRemoteConnectionHandle.kt     | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/main/kotlin/com/coder/gateway/CoderRemoteConnectionHandle.kt b/src/main/kotlin/com/coder/gateway/CoderRemoteConnectionHandle.kt
index f4e86850..e976d7d0 100644
--- a/src/main/kotlin/com/coder/gateway/CoderRemoteConnectionHandle.kt
+++ b/src/main/kotlin/com/coder/gateway/CoderRemoteConnectionHandle.kt
@@ -357,7 +357,7 @@ class CoderRemoteConnectionHandle {
     private fun exec(workspace: WorkspaceProjectIDE, command: String): String {
         logger.info("Running command `$command` in ${workspace.hostname}:${workspace.idePathOnHost}/bin...")
         return ProcessExecutor()
-            .command("ssh", "-t", workspace.hostname, "cd '${workspace.idePathOnHost}' ; cd bin ; $command")
+            .command("ssh", "-t", CoderCLIManager.getBackgroundHostName(workspace.hostname), "cd '${workspace.idePathOnHost}' ; cd bin ; $command")
             .exitValues(0)
             .readOutput(true)
             .execute()

From e6e77c2321f89b6801ecbce228241d6d136400e0 Mon Sep 17 00:00:00 2001
From: Garrett Delfosse <garrett@coder.com>
Date: Tue, 25 Jun 2024 18:38:24 +0000
Subject: [PATCH 08/10] remove env

---
 src/main/kotlin/com/coder/gateway/cli/CoderCLIManager.kt | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/src/main/kotlin/com/coder/gateway/cli/CoderCLIManager.kt b/src/main/kotlin/com/coder/gateway/cli/CoderCLIManager.kt
index f64cec07..41089a5f 100644
--- a/src/main/kotlin/com/coder/gateway/cli/CoderCLIManager.kt
+++ b/src/main/kotlin/com/coder/gateway/cli/CoderCLIManager.kt
@@ -281,7 +281,7 @@ class CoderCLIManager(
                 transform = {
                     """
                     Host ${getHostName(deploymentURL, it)}
-                      ProxyCommand CODER_SSH_USAGE_APP=jetbrains ${proxyArgs.joinToString(" ")} $it
+                      ProxyCommand ${proxyArgs.joinToString(" ")} $it
                       ConnectTimeout 0
                       StrictHostKeyChecking no
                       UserKnownHostsFile /dev/null
@@ -300,8 +300,7 @@ class CoderCLIManager(
                               SetEnv CODER_SSH_SESSION_TYPE=JetBrains
                             """.trimIndent()
                                 .plus(extraConfig)
-                        )
-                        .replace("\n", System.lineSeparator())
+                        ).replace("\n", System.lineSeparator())
                 },
             )
 

From 54232b7d10240980dfcce5316e68c38cd50c92c3 Mon Sep 17 00:00:00 2001
From: Garrett Delfosse <garrett@coder.com>
Date: Tue, 25 Jun 2024 18:43:00 +0000
Subject: [PATCH 09/10] fix newline

---
 src/main/kotlin/com/coder/gateway/cli/CoderCLIManager.kt | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/main/kotlin/com/coder/gateway/cli/CoderCLIManager.kt b/src/main/kotlin/com/coder/gateway/cli/CoderCLIManager.kt
index 41089a5f..8efb636a 100644
--- a/src/main/kotlin/com/coder/gateway/cli/CoderCLIManager.kt
+++ b/src/main/kotlin/com/coder/gateway/cli/CoderCLIManager.kt
@@ -289,6 +289,7 @@ class CoderCLIManager(
                       SetEnv CODER_SSH_SESSION_TYPE=JetBrains
                     """.trimIndent()
                         .plus(extraConfig)
+                        .plus("\n")
                         .plus(
                             """
                             Host ${getBackgroundHostName(deploymentURL, it)}

From cf673a197221db056fbeb0ab1a753def211e1e36 Mon Sep 17 00:00:00 2001
From: Garrett Delfosse <garrett@coder.com>
Date: Tue, 25 Jun 2024 18:55:36 +0000
Subject: [PATCH 10/10] disable on bg hostname

---
 src/main/kotlin/com/coder/gateway/cli/CoderCLIManager.kt | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/src/main/kotlin/com/coder/gateway/cli/CoderCLIManager.kt b/src/main/kotlin/com/coder/gateway/cli/CoderCLIManager.kt
index 8efb636a..4691c095 100644
--- a/src/main/kotlin/com/coder/gateway/cli/CoderCLIManager.kt
+++ b/src/main/kotlin/com/coder/gateway/cli/CoderCLIManager.kt
@@ -255,7 +255,7 @@ class CoderCLIManager(
         val startBlock = "# --- START CODER JETBRAINS $host"
         val endBlock = "# --- END CODER JETBRAINS $host"
         val isRemoving = workspaceNames.isEmpty()
-        val proxyArgs =
+        val baseArgs =
             listOfNotNull(
                 escape(localBinaryPath.toString()),
                 "--global-config",
@@ -265,8 +265,9 @@ class CoderCLIManager(
                 "ssh",
                 "--stdio",
                 if (settings.disableAutostart && feats.disableAutostart) "--disable-autostart" else null,
-                if (feats.reportWorkspaceUsage) "--usage-app=jetbrains" else null,
             )
+        val proxyArgs = baseArgs + listOfNotNull(if (feats.reportWorkspaceUsage) "--usage-app=jetbrains" else null)
+        val backgroundProxyArgs = baseArgs + listOfNotNull(if (feats.reportWorkspaceUsage) "--usage-app=disable" else null)
         val extraConfig =
             if (settings.sshConfigOptions.isNotBlank()) {
                 "\n" + settings.sshConfigOptions.prependIndent("  ")
@@ -293,7 +294,7 @@ class CoderCLIManager(
                         .plus(
                             """
                             Host ${getBackgroundHostName(deploymentURL, it)}
-                              ProxyCommand ${proxyArgs.joinToString(" ")} $it
+                              ProxyCommand ${backgroundProxyArgs.joinToString(" ")} $it
                               ConnectTimeout 0
                               StrictHostKeyChecking no
                               UserKnownHostsFile /dev/null