about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--nixos/tests/all-tests.nix1
-rw-r--r--nixos/tests/vscode-remote-ssh.nix124
-rw-r--r--pkgs/applications/editors/vscode/extensions/ms-vscode-remote.remote-ssh/default.nix47
-rw-r--r--pkgs/applications/editors/vscode/generic.nix4
-rwxr-xr-xpkgs/applications/editors/vscode/update-vscode.sh17
-rw-r--r--pkgs/applications/editors/vscode/vscode.nix24
-rw-r--r--pkgs/build-support/src-only/default.nix3
7 files changed, 194 insertions, 26 deletions
diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix
index 019d2c0ee70b3..4857a45b9a039 100644
--- a/nixos/tests/all-tests.nix
+++ b/nixos/tests/all-tests.nix
@@ -814,6 +814,7 @@ in {
   victoriametrics = handleTest ./victoriametrics.nix {};
   vikunja = handleTest ./vikunja.nix {};
   virtualbox = handleTestOn ["x86_64-linux"] ./virtualbox.nix {};
+  vscode-remote-ssh = handleTestOn ["x86_64-linux"] ./vscode-remote-ssh.nix {};
   vscodium = discoverTests (import ./vscodium.nix);
   vsftpd = handleTest ./vsftpd.nix {};
   warzone2100 = handleTest ./warzone2100.nix {};
diff --git a/nixos/tests/vscode-remote-ssh.nix b/nixos/tests/vscode-remote-ssh.nix
new file mode 100644
index 0000000000000..de7cc6badc9a2
--- /dev/null
+++ b/nixos/tests/vscode-remote-ssh.nix
@@ -0,0 +1,124 @@
+import ./make-test-python.nix ({ lib, ... }@args: let
+  pkgs = args.pkgs.extend (self: super: {
+    stdenv = super.stdenv.override {
+      config = super.config // {
+        allowUnfreePredicate = pkg: builtins.elem (lib.getName pkg) [
+          "vscode" "vscode-with-extensions" "vscode-extension-ms-vscode-remote-remote-ssh"
+        ];
+      };
+    };
+  });
+
+  inherit (import ./ssh-keys.nix pkgs) snakeOilPrivateKey snakeOilPublicKey;
+
+  inherit (pkgs.vscode.passthru) rev vscodeServer;
+in {
+  name = "vscode-remote-ssh";
+  meta.maintainers = with lib.maintainers; [ Enzime ];
+
+  nodes = let
+    serverAddress = "192.168.0.2";
+    clientAddress = "192.168.0.1";
+  in {
+    server = { ... }: {
+      networking.interfaces.eth1.ipv4.addresses = [ { address = serverAddress; prefixLength = 24; } ];
+      services.openssh.enable = true;
+      users.users.root.openssh.authorizedKeys.keys = [ snakeOilPublicKey ];
+      virtualisation.additionalPaths = with pkgs; [ patchelf bintools stdenv.cc.cc.lib ];
+    };
+    client = { ... }: {
+      imports = [ ./common/x11.nix ./common/user-account.nix ];
+      networking.interfaces.eth1.ipv4.addresses = [ { address = clientAddress; prefixLength = 24; } ];
+      networking.hosts.${serverAddress} = [ "server" ];
+      test-support.displayManager.auto.user = "alice";
+      environment.systemPackages = [
+        (pkgs.vscode-with-extensions.override {
+          vscodeExtensions = [
+            pkgs.vscode-extensions.ms-vscode-remote.remote-ssh
+          ];
+        })
+      ];
+    };
+  };
+
+  enableOCR = true;
+
+  testScript = let
+    jq = "${pkgs.jq}/bin/jq";
+
+    sshConfig = builtins.toFile "ssh.conf" ''
+      UserKnownHostsFile=/dev/null
+      StrictHostKeyChecking=no
+    '';
+
+    vscodeConfig = builtins.toFile "settings.json" ''
+      {
+        "window.zoomLevel": 1,
+        "security.workspace.trust.startupPrompt": "always"
+      }
+    '';
+  in ''
+    def connect_with_remote_ssh(screenshot, should_succeed):
+      print(f"connect_with_remote_ssh({screenshot=}, {should_succeed=})")
+
+      if server.execute("test -d ~/.vscode-server")[0] == 0:
+        server.succeed("rm -r ~/.vscode-server")
+
+      server.succeed("mkdir -p ~/.vscode-server/bin")
+      server.succeed("cp -r ${vscodeServer} ~/.vscode-server/bin/${rev}")
+
+      client.succeed("sudo -u alice code --remote=ssh-remote+root@server /root")
+      client.wait_for_window("Visual Studio Code")
+
+      client.wait_for_text("Do you trust the authors" if should_succeed else "Disconnected from SSH")
+      client.screenshot(screenshot)
+
+      if should_succeed:
+        # Press the Don't Trust button
+        client.send_key("tab")
+        client.send_key("tab")
+        client.send_key("tab")
+        client.send_key("\n")
+      else:
+        # Close the error dialog
+        client.send_key("esc")
+
+      # Don't send Ctrl-q too quickly otherwise it might not get sent to VS Code
+      client.sleep(1)
+      client.send_key("ctrl-q")
+      client.wait_until_fails("pidof code")
+
+
+    start_all()
+    server.wait_for_open_port(22)
+
+    VSCODE_COMMIT = server.execute("${jq} -r .commit ${pkgs.vscode}/lib/vscode/resources/app/product.json")[1].rstrip()
+    SERVER_COMMIT = server.execute("${jq} -r .commit ${vscodeServer}/product.json")[1].rstrip()
+
+    print(f"{VSCODE_COMMIT=} {SERVER_COMMIT=}")
+    assert VSCODE_COMMIT == SERVER_COMMIT, "VSCODE_COMMIT and SERVER_COMMIT do not match"
+
+    client.wait_until_succeeds("ping -c1 server")
+    client.succeed("sudo -u alice mkdir ~alice/.ssh")
+    client.succeed("sudo -u alice install -Dm 600 ${snakeOilPrivateKey} ~alice/.ssh/id_ecdsa")
+    client.succeed("sudo -u alice install ${sshConfig} ~alice/.ssh/config")
+    client.succeed("sudo -u alice install -Dm 644 ${vscodeConfig} ~alice/.config/Code/User/settings.json")
+
+    client.wait_for_x()
+    client.wait_for_file("~alice/.Xauthority")
+    client.succeed("xauth merge ~alice/.Xauthority")
+    # Move the mouse out of the way
+    client.succeed("${pkgs.xdotool}/bin/xdotool mousemove 0 0")
+
+    with subtest("fails to connect when nixpkgs isn't available"):
+      server.fail("nix-build '<nixpkgs>' -A hello")
+      connect_with_remote_ssh(screenshot="no_node_installed", should_succeed=False)
+      server.succeed("test -e ~/.vscode-server/bin/${rev}/node")
+      server.fail("~/.vscode-server/bin/${rev}/node -v")
+
+    with subtest("connects when server can patch Node"):
+      server.succeed("mkdir -p /nix/var/nix/profiles/per-user/root/channels")
+      server.succeed("ln -s ${pkgs.path} /nix/var/nix/profiles/per-user/root/channels/nixos")
+      connect_with_remote_ssh(screenshot="build_node_with_nix", should_succeed=True)
+  '';
+})
diff --git a/pkgs/applications/editors/vscode/extensions/ms-vscode-remote.remote-ssh/default.nix b/pkgs/applications/editors/vscode/extensions/ms-vscode-remote.remote-ssh/default.nix
index de191e97e0dc2..d479e7d1fd595 100644
--- a/pkgs/applications/editors/vscode/extensions/ms-vscode-remote.remote-ssh/default.nix
+++ b/pkgs/applications/editors/vscode/extensions/ms-vscode-remote.remote-ssh/default.nix
@@ -1,4 +1,5 @@
 { lib
+, nixosTests
 , vscode-utils
 , useLocalExtensions ? false
 }:
@@ -9,8 +10,6 @@
 let
   inherit (vscode-utils) buildVscodeMarketplaceExtension;
 
-  nodeVersion = "16";
-
   # As VS Code executes this code on the remote machine
   # we test to see if we can build Node from Nixpkgs
   # otherwise we check if the globally installed Node
@@ -23,38 +22,44 @@ let
     serverNode="$serverDir/node"
     echo "VS Code Node: $serverNode"
 
-    # Check if VS Code Server has a non-working Node or the wrong version of Node
-    if ! nodeVersion=$($serverNode -v) || [ "\''${nodeVersion:1:2}" != "${nodeVersion}" ]; then
+    # Check if Node included with VS Code Server runs
+    if ! nodeVersion=$($serverNode -v); then
       echo "VS Code Node Version: $nodeVersion"
 
-      if nix-build "<nixpkgs>" -A nodejs-${nodeVersion}_x --out-link "$serverDir/nix" && [ -e "$serverDir/nix/bin/node" ]; then
-        nodePath="$serverDir/nix/bin/node"
+      if ! nix-build "<nixpkgs>" -A patchelf --out-link "$serverDir/patchelf" || ! "$serverDir/patchelf/bin/patchelf" --version; then
+        echo "Failed to get patchelf from nixpkgs"
+      fi
+
+      if [ -e $serverNode.orig ]; then
+        cp $serverNode.orig $serverNode
+      else
+        cp $serverNode $serverNode.orig
       fi
 
-      echo "Node from Nix: $nodePath"
+      if ! nix-build "<nixpkgs>" -A bintools --out-link $serverDir/bintools; then
+        echo "Failed to build bintools from nixpkgs"
+      fi
 
-      nodeVersion=$($nodePath -v)
-      echo "Node from Nix Version: $nodeVersion"
+      INTERPRETER=$(cat $serverDir/bintools/nix-support/dynamic-linker)
 
-      if [ "\''${nodeVersion:1:2}" != "${nodeVersion}" ]; then
-        echo "Getting Node from Nix failed, use Local Node instead"
-        nodePath=$(which node)
-        echo "Local Node: $nodePath"
-        nodeVersion=$($nodePath -v)
-        echo "Local Node Version: $nodeVersion"
+      echo "Interpreter from bintools: $INTERPRETER"
+
+      if ! nix-build "<nixpkgs>" -A stdenv.cc.cc.lib --out-link $serverDir/cc; then
+        echo "Failed to build stdenv.cc.cc.lib from nixpkgs"
       fi
 
-      if [ "\''${nodeVersion:1:2}" == "${nodeVersion}" ]; then
-        echo PATCH: replacing $serverNode with $nodePath
-        ln -sf $nodePath $serverNode
+      if ! $serverDir/patchelf/bin/patchelf --set-interpreter $INTERPRETER --set-rpath $serverDir/cc-lib/lib $serverNode; then
+        echo "Failed to patch Node binary"
       fi
+
+      rm "$serverDir/patchelf"
     fi
 
     nodeVersion=$($serverNode -v)
     echo "VS Code Node Version: $nodeVersion"
 
-    if [ "\''${nodeVersion:1:2}" != "${nodeVersion}" ]; then
-      echo "Unsupported VS Code Node version: $nodeVersion", quitting
+    if ! nodeVersion=$($serverNode -v); then
+      echo "Unable to fix Node binary, quitting"
       fail_with_exitcode ''${o.InstallExitCode.ServerTransferFailed}
     fi
 
@@ -87,6 +92,8 @@ buildVscodeMarketplaceExtension {
       --replace '# Start the server\n' '${patch}'
   '';
 
+  passthru.tests = { inherit (nixosTests) vscode-remote-ssh; };
+
   meta = {
     description = "Use any remote machine with a SSH server as your development environment.";
     license = lib.licenses.unfree;
diff --git a/pkgs/applications/editors/vscode/generic.nix b/pkgs/applications/editors/vscode/generic.nix
index 7b7007910a5c6..6d1c20c855415 100644
--- a/pkgs/applications/editors/vscode/generic.nix
+++ b/pkgs/applications/editors/vscode/generic.nix
@@ -13,6 +13,8 @@
 , version, src, meta, sourceRoot, commandLineArgs
 , executableName, longName, shortName, pname, updateScript
 , dontFixup ? false
+, rev ? null, vscodeServer ? null
+
 # sourceExecutableName is the name of the binary in the source archive, over
 # which we have no control
 , sourceExecutableName ? executableName
@@ -30,6 +32,8 @@ let
       inherit executableName longName tests updateScript;
       fhs = fhs {};
       fhsWithPackages = f: fhs { additionalPkgs = f; };
+    } // lib.optionalAttrs (vscodeServer != null) {
+      inherit rev vscodeServer;
     };
 
     desktopItem = makeDesktopItem {
diff --git a/pkgs/applications/editors/vscode/update-vscode.sh b/pkgs/applications/editors/vscode/update-vscode.sh
index 67ec7a21b3461..d1df522f40247 100755
--- a/pkgs/applications/editors/vscode/update-vscode.sh
+++ b/pkgs/applications/editors/vscode/update-vscode.sh
@@ -19,9 +19,22 @@ fi
 VSCODE_VER=$(curl --fail --silent https://api.github.com/repos/Microsoft/vscode/releases/latest | jq --raw-output .tag_name)
 sed -i "s/version = \".*\"/version = \"${VSCODE_VER}\"/" "$ROOT/vscode.nix"
 
+TEMP_FOLDER=$(mktemp -d)
+
 VSCODE_X64_LINUX_URL="https://update.code.visualstudio.com/${VSCODE_VER}/linux-x64/stable"
-VSCODE_X64_LINUX_SHA256=$(nix-prefetch-url ${VSCODE_X64_LINUX_URL})
-sed -i "s/x86_64-linux = \".\{52\}\"/x86_64-linux = \"${VSCODE_X64_LINUX_SHA256}\"/" "$ROOT/vscode.nix"
+
+# Split output by newlines into Bash array
+readarray -t VSCODE_X64_LINUX <<< $(nix-prefetch-url --print-path ${VSCODE_X64_LINUX_URL})
+
+sed -i "s/x86_64-linux = \".\{52\}\"/x86_64-linux = \"${VSCODE_X64_LINUX[0]}\"/" "$ROOT/vscode.nix"
+
+tar xf ${VSCODE_X64_LINUX[1]} -C $TEMP_FOLDER
+VSCODE_COMMIT=$(jq --raw-output .commit $TEMP_FOLDER/VSCode-linux-x64/resources/app/product.json)
+sed -i "s/rev = \".\{40\}\"/rev = \"${VSCODE_COMMIT}\"/" "$ROOT/vscode.nix"
+
+SERVER_X64_LINUX_URL="https://update.code.visualstudio.com/commit:${VSCODE_COMMIT}/server-linux-x64/stable"
+SERVER_X64_LINUX_SHA256=$(nix-prefetch-url ${SERVER_X64_LINUX_URL})
+sed -i "s/sha256 = \".\{51,52\}\"/sha256 = \"${SERVER_X64_LINUX_SHA256}\"/" "$ROOT/vscode.nix"
 
 VSCODE_X64_DARWIN_URL="https://update.code.visualstudio.com/${VSCODE_VER}/darwin/stable"
 VSCODE_X64_DARWIN_SHA256=$(nix-prefetch-url ${VSCODE_X64_DARWIN_URL})
diff --git a/pkgs/applications/editors/vscode/vscode.nix b/pkgs/applications/editors/vscode/vscode.nix
index e1f291ebcd38d..744d9ea9186e5 100644
--- a/pkgs/applications/editors/vscode/vscode.nix
+++ b/pkgs/applications/editors/vscode/vscode.nix
@@ -1,4 +1,9 @@
-{ stdenv, lib, callPackage, fetchurl
+{ stdenv
+, lib
+, callPackage
+, fetchurl
+, nixosTests
+, srcOnly
 , isInsiders ? false
 , commandLineArgs ? ""
 , useVSCodeRipgrep ? stdenv.isDarwin
@@ -32,6 +37,9 @@ in
     version = "1.79.1";
     pname = "vscode";
 
+    # This is used for VS Code - Remote SSH test
+    rev = "b380da4ef1ee00e224a15c1d4d9793e27c2b6302";
+
     executableName = "code" + lib.optionalString isInsiders "-insiders";
     longName = "Visual Studio Code" + lib.optionalString isInsiders " - Insiders";
     shortName = "Code" + lib.optionalString isInsiders " - Insiders";
@@ -48,6 +56,18 @@ in
 
     sourceRoot = "";
 
+    # As tests run without networking, we need to download this for the Remote SSH server
+    vscodeServer = srcOnly {
+      name = "vscode-server-${rev}.tar.gz";
+      src = fetchurl {
+        name = "vscode-server-${rev}.tar.gz";
+        url = "https://update.code.visualstudio.com/commit:${rev}/server-linux-x64/stable";
+        sha256 = "0732wpl4fjknhn423k23zrcqz9psjj1iy8lqa0fc8970n1m7i58b";
+      };
+    };
+
+    tests = { inherit (nixosTests) vscode-remote-ssh; };
+
     updateScript = ./update-vscode.sh;
 
     # Editing the `code` binary within the app bundle causes the bundle's signature
@@ -71,7 +91,7 @@ in
       homepage = "https://code.visualstudio.com/";
       downloadPage = "https://code.visualstudio.com/Updates";
       license = licenses.unfree;
-      maintainers = with maintainers; [ eadwu synthetica maxeaubrey bobby285271 ];
+      maintainers = with maintainers; [ eadwu synthetica maxeaubrey bobby285271 Enzime ];
       platforms = [ "x86_64-linux" "x86_64-darwin" "aarch64-darwin" "aarch64-linux" "armv7l-linux" ];
     };
   }
diff --git a/pkgs/build-support/src-only/default.nix b/pkgs/build-support/src-only/default.nix
index 6cf5c2ad482b8..2b0db0e267aa7 100644
--- a/pkgs/build-support/src-only/default.nix
+++ b/pkgs/build-support/src-only/default.nix
@@ -1,7 +1,6 @@
 { stdenv }:
 # srcOnly is a utility builder that only fetches and unpacks the given `src`,
-# maybe pathings it in the process with the optional `patches` and
-# `buildInputs` attributes.
+# and optionally patching with `patches` or adding build inputs.
 #
 # It can be invoked directly, or be used to wrap an existing derivation. Eg:
 #