From 6e6f02b5e2c31f6c081492390a59eb4400acbb03 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 5 Jun 2026 12:43:03 +0000 Subject: [PATCH 1/4] Initial plan From 90726fc96db7420e7ea9f532ce6dda20b837a6dc Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 5 Jun 2026 12:49:15 +0000 Subject: [PATCH 2/4] fix: align verbose ssh handling in tryToConnect --- server/app/core/sshManager.js | 3 +- server/app/handlers/tryToConnect.js | 4 +- server/test/app/handlers/tryToConnect.js | 108 +++++++++++++++++++++++ 3 files changed, 112 insertions(+), 3 deletions(-) create mode 100644 server/test/app/handlers/tryToConnect.js diff --git a/server/app/core/sshManager.js b/server/app/core/sshManager.js index 79a956952..e848956b1 100644 --- a/server/app/core/sshManager.js +++ b/server/app/core/sshManager.js @@ -247,5 +247,6 @@ module.exports = { getSshHostinfo, removeSsh, askPassword, - createSsh + createSsh, + isVerboseSshEnabled }; diff --git a/server/app/handlers/tryToConnect.js b/server/app/handlers/tryToConnect.js index bc62636f5..9b5d2deeb 100644 --- a/server/app/handlers/tryToConnect.js +++ b/server/app/handlers/tryToConnect.js @@ -8,7 +8,7 @@ const SshClientWrapper = require("ssh-client-wrapper"); const { getLogger } = require("../logSettings"); const logger = getLogger(); const { remoteHost } = require("../db/db"); -const { askPassword } = require("../core/sshManager.js"); +const { askPassword, isVerboseSshEnabled } = require("../core/sshManager.js"); /** * try to connect remote host via ssh @@ -19,7 +19,7 @@ const { askPassword } = require("../core/sshManager.js"); async function onTryToConnect(clientID, hostInfo, cb) { hostInfo.password = askPassword.bind(null, clientID, hostInfo.name, "password", null); hostInfo.passphrase = askPassword.bind(null, clientID, hostInfo.name, "passphrase", null); - if (process.env.WHEEL_VERBOSE_SSH) { + if (isVerboseSshEnabled()) { hostInfo.sshOpt = ["-vvv"]; } const ssh = new SshClientWrapper(hostInfo); diff --git a/server/test/app/handlers/tryToConnect.js b/server/test/app/handlers/tryToConnect.js new file mode 100644 index 000000000..7702b9bef --- /dev/null +++ b/server/test/app/handlers/tryToConnect.js @@ -0,0 +1,108 @@ +"use strict"; +const os = require("os"); +const path = require("path"); +const fs = require("fs-extra"); + +const chai = require("chai"); +const expect = chai.expect; +const sinon = require("sinon"); +chai.use(require("sinon-chai")); +const rewire = require("rewire"); + +describe("tryToConnect UT", ()=>{ + const originalHome = process.env.HOME; + const originalWheelUseHttp = process.env.WHEEL_USE_HTTP; + const originalWheelVerboseSsh = process.env.WHEEL_VERBOSE_SSH; + let tempHome; + let tryToConnect; + let onTryToConnect; + let SshClientWrapperMock; + let canConnectMock; + let disconnectMock; + let askPasswordMock; + let cb; + + before(async ()=>{ + tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "wheel-try-connect-")); + process.env.HOME = tempHome; + process.env.WHEEL_USE_HTTP = "1"; + await fs.ensureDir(path.join(tempHome, ".wheel")); + await Promise.all([ + fs.writeJson(path.join(tempHome, ".wheel", "remotehost.json"), []), + fs.writeJson(path.join(tempHome, ".wheel", "projectList.json"), []), + fs.writeJson(path.join(tempHome, ".wheel", "jobScriptTemplate.json"), []) + ]); + }); + + beforeEach(()=>{ + cb = sinon.stub(); + canConnectMock = sinon.stub().resolves(); + disconnectMock = sinon.stub(); + askPasswordMock = sinon.stub(); + + tryToConnect = rewire("../../../app/handlers/tryToConnect.js"); + SshClientWrapperMock = sinon.stub().callsFake((hostInfo)=>{ + return { + hostInfo, + canConnect: canConnectMock, + disconnect: disconnectMock + }; + }); + + tryToConnect.__set__({ + SshClientWrapper: SshClientWrapperMock, + askPassword: askPasswordMock, + logger: { + debug: sinon.stub(), + info: sinon.stub(), + error: sinon.stub() + } + }); + onTryToConnect = tryToConnect.__get__("onTryToConnect"); + }); + + afterEach(()=>{ + sinon.restore(); + if (originalWheelVerboseSsh !== undefined) { + process.env.WHEEL_VERBOSE_SSH = originalWheelVerboseSsh; + } else { + delete process.env.WHEEL_VERBOSE_SSH; + } + }); + + after(async ()=>{ + if (originalHome !== undefined) { + process.env.HOME = originalHome; + } else { + delete process.env.HOME; + } + if (originalWheelUseHttp !== undefined) { + process.env.WHEEL_USE_HTTP = originalWheelUseHttp; + } else { + delete process.env.WHEEL_USE_HTTP; + } + await fs.remove(tempHome); + }); + + it("should set sshOpt when WHEEL_VERBOSE_SSH is truthy", async ()=>{ + process.env.WHEEL_VERBOSE_SSH = "true"; + const hostInfo = { name: "testHost", host: "localhost", port: 22, user: "test" }; + + await onTryToConnect("client-1", hostInfo, cb); + + expect(hostInfo.sshOpt).to.deep.equal(["-vvv"]); + expect(SshClientWrapperMock).to.have.been.calledOnceWithExactly(hostInfo); + expect(cb).to.have.been.calledOnceWithExactly("success"); + }); + + it("should not set sshOpt when WHEEL_VERBOSE_SSH is false-like", async ()=>{ + process.env.WHEEL_VERBOSE_SSH = "false"; + const hostInfo = { name: "testHost", host: "localhost", port: 22, user: "test" }; + + await onTryToConnect("client-1", hostInfo, cb); + + expect(hostInfo).to.not.have.property("sshOpt"); + expect(SshClientWrapperMock).to.have.been.calledOnceWithExactly(hostInfo); + expect(cb).to.have.been.calledOnceWithExactly("success"); + }); +}); From f13a0aefd114f30808a561b7a4ab9e320aa34079 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 5 Jun 2026 12:51:14 +0000 Subject: [PATCH 3/4] test: cover verbose ssh handling in tryToConnect --- server/app/handlers/tryToConnect.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/server/app/handlers/tryToConnect.js b/server/app/handlers/tryToConnect.js index 9b5d2deeb..229c24255 100644 --- a/server/app/handlers/tryToConnect.js +++ b/server/app/handlers/tryToConnect.js @@ -15,6 +15,7 @@ const { askPassword, isVerboseSshEnabled } = require("../core/sshManager.js"); * @param {string} clientID - socketIO client's ID string * @param {object} hostInfo - target host's information * @param {Function} cb - call back function called with string "success" or "error" + * @returns {Promise} */ async function onTryToConnect(clientID, hostInfo, cb) { hostInfo.password = askPassword.bind(null, clientID, hostInfo.name, "password", null); @@ -38,6 +39,14 @@ async function onTryToConnect(clientID, hostInfo, cb) { ssh.disconnect(); return cb("success"); } + +/** + * try to connect remote host via ssh with host id + * @param {string} clientID - socketIO client's ID string + * @param {string} id - remote host id + * @param {Function} cb - call back function called with string "success" or "error" + * @returns {Promise} + */ async function onTryToConnectById(clientID, id, cb) { const hostInfo = remoteHost.get(id); await onTryToConnect(clientID, hostInfo, cb); From fd05828fbfdd3a18dd0c936e60e31d7fcf0f6a12 Mon Sep 17 00:00:00 2001 From: "version-number-updater[bot]" Date: Fri, 5 Jun 2026 22:16:27 +0900 Subject: [PATCH 4/4] [skip ci] update version number --- server/app/db/version.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/app/db/version.json b/server/app/db/version.json index a9ad41afd..e44604107 100644 --- a/server/app/db/version.json +++ b/server/app/db/version.json @@ -1 +1 @@ -{"version": "2026-0605-211714" } \ No newline at end of file +{"version": "2026-0605-221627" } \ No newline at end of file