[Init] Initial commit - NetMesh terminal manager
Some checks failed
build-packages / resolve bundled mosh-client (push) Has been cancelled
build-packages / resolve bundled et-client (push) Has been cancelled
build-packages / build-macos (push) Has been cancelled
build-packages / build-windows (push) Has been cancelled
build-packages / build-linux-x64 (push) Has been cancelled
build-packages / build-linux-arm64 (push) Has been cancelled
build-packages / release (push) Has been cancelled
build-packages / update Nix release metadata (push) Has been cancelled
build-packages / bump homebrew tap (push) Has been cancelled
test / lint-and-test (push) Has been cancelled
AI automation / Route event (push) Has been cancelled
AI automation / Hand reopened issue to maintainers (push) Has been cancelled
AI automation / Clean source issue state (push) Has been cancelled
AI automation / Reconcile handoffs (push) Has been cancelled
AI automation / Classify issue (push) Has been cancelled
AI automation / Claude Code smoke (push) Has been cancelled
AI automation / Review issue follow-up (push) Has been cancelled
AI automation / Publish issue follow-up (push) Has been cancelled
AI automation / Implement with Claude Code (push) Has been cancelled
AI automation / Publish implement PR (push) Has been cancelled
AI automation / Continue queued issue comments (push) Has been cancelled
AI automation / Codex review loop (push) Has been cancelled
AI automation / Publish Codex fix (push) Has been cancelled
AI automation / Clear Codex dispatch marker (push) Has been cancelled
AI automation / Own PR re-request Codex (push) Has been cancelled
AI automation / External PR re-request Codex (push) Has been cancelled
AI automation / Poll Codex reaction / retry (push) Has been cancelled
build-et-binaries / build-linux-x64 (push) Has been cancelled
build-et-binaries / build-linux-arm64 (push) Has been cancelled
build-et-binaries / build-macos-universal (push) Has been cancelled
build-et-binaries / build-windows-x64 (push) Has been cancelled
build-et-binaries / release (push) Has been cancelled
Some checks failed
build-packages / resolve bundled mosh-client (push) Has been cancelled
build-packages / resolve bundled et-client (push) Has been cancelled
build-packages / build-macos (push) Has been cancelled
build-packages / build-windows (push) Has been cancelled
build-packages / build-linux-x64 (push) Has been cancelled
build-packages / build-linux-arm64 (push) Has been cancelled
build-packages / release (push) Has been cancelled
build-packages / update Nix release metadata (push) Has been cancelled
build-packages / bump homebrew tap (push) Has been cancelled
test / lint-and-test (push) Has been cancelled
AI automation / Route event (push) Has been cancelled
AI automation / Hand reopened issue to maintainers (push) Has been cancelled
AI automation / Clean source issue state (push) Has been cancelled
AI automation / Reconcile handoffs (push) Has been cancelled
AI automation / Classify issue (push) Has been cancelled
AI automation / Claude Code smoke (push) Has been cancelled
AI automation / Review issue follow-up (push) Has been cancelled
AI automation / Publish issue follow-up (push) Has been cancelled
AI automation / Implement with Claude Code (push) Has been cancelled
AI automation / Publish implement PR (push) Has been cancelled
AI automation / Continue queued issue comments (push) Has been cancelled
AI automation / Codex review loop (push) Has been cancelled
AI automation / Publish Codex fix (push) Has been cancelled
AI automation / Clear Codex dispatch marker (push) Has been cancelled
AI automation / Own PR re-request Codex (push) Has been cancelled
AI automation / External PR re-request Codex (push) Has been cancelled
AI automation / Poll Codex reaction / retry (push) Has been cancelled
build-et-binaries / build-linux-x64 (push) Has been cancelled
build-et-binaries / build-linux-arm64 (push) Has been cancelled
build-et-binaries / build-macos-universal (push) Has been cancelled
build-et-binaries / build-windows-x64 (push) Has been cancelled
build-et-binaries / release (push) Has been cancelled
This commit is contained in:
136
electron/bridges/sshBridge/execCommand.systemAgent.test.cjs
Normal file
136
electron/bridges/sshBridge/execCommand.systemAgent.test.cjs
Normal file
@@ -0,0 +1,136 @@
|
||||
const test = require("node:test");
|
||||
const assert = require("node:assert/strict");
|
||||
const { EventEmitter } = require("node:events");
|
||||
|
||||
const { createExecCommandApi } = require("./execCommand.cjs");
|
||||
|
||||
function createHarness({ identitiesOnly }) {
|
||||
const preparedAgent = { kind: "system-agent" };
|
||||
const calls = {
|
||||
connectOptions: null,
|
||||
defaultKeyScans: 0,
|
||||
identityFileLoads: 0,
|
||||
inlineKeyLoads: 0,
|
||||
endCount: 0,
|
||||
authConfig: null,
|
||||
agentSocketChecks: 0,
|
||||
};
|
||||
|
||||
class MockSSHClient extends EventEmitter {
|
||||
connect(options) {
|
||||
calls.connectOptions = options;
|
||||
queueMicrotask(() => this.emit("error", new Error("stop after options capture")));
|
||||
}
|
||||
|
||||
end() {
|
||||
calls.endCount += 1;
|
||||
}
|
||||
|
||||
exec() {}
|
||||
}
|
||||
|
||||
const api = createExecCommandApi({
|
||||
SSHClient: MockSSHClient,
|
||||
NetcattyAgent: class {},
|
||||
randomUUID: () => "exec-test",
|
||||
console,
|
||||
setTimeout,
|
||||
clearTimeout,
|
||||
Error,
|
||||
prepareSystemSshAgentForAuth: async (payload) => {
|
||||
if (payload.useSshAgent !== true) return null;
|
||||
assert.equal(payload.useSshAgent, true);
|
||||
assert.equal(payload.identitiesOnly, identitiesOnly);
|
||||
return preparedAgent;
|
||||
},
|
||||
getAvailableAgentSocket: async () => {
|
||||
calls.agentSocketChecks += 1;
|
||||
return null;
|
||||
},
|
||||
findAllDefaultPrivateKeysFromHelper: async () => {
|
||||
calls.defaultKeyScans += 1;
|
||||
return [{ privateKey: "default-key" }];
|
||||
},
|
||||
preparePrivateKeyForAuth: async () => {
|
||||
calls.inlineKeyLoads += 1;
|
||||
return { privateKey: "inline-key" };
|
||||
},
|
||||
loadIdentityFileForAuth: async () => {
|
||||
calls.identityFileLoads += 1;
|
||||
return { privateKey: "identity-file-key" };
|
||||
},
|
||||
isPassphraseCancelledError: () => false,
|
||||
resolveSshConnectionTimeouts: () => ({
|
||||
tcpConnectTimeoutMs: 20000,
|
||||
authReadyTimeoutMs: 120000,
|
||||
}),
|
||||
buildAlgorithms: () => undefined,
|
||||
buildAuthHandler: (options) => {
|
||||
calls.authConfig = options;
|
||||
return { authHandler: ["agent"], agent: options.agent };
|
||||
},
|
||||
applyAuthToConnOpts: (connectOptions, authConfig) => {
|
||||
connectOptions.agent = authConfig.agent;
|
||||
connectOptions.authHandler = authConfig.authHandler;
|
||||
},
|
||||
createKeyboardInteractiveHandler: () => () => {},
|
||||
});
|
||||
|
||||
return { api, calls, preparedAgent };
|
||||
}
|
||||
|
||||
test("execCommand disables an unavailable optional agent before automatic fallback", async () => {
|
||||
const { api, calls } = createHarness({ identitiesOnly: false });
|
||||
|
||||
await assert.rejects(
|
||||
() => api.execCommand(
|
||||
{ sender: {} },
|
||||
{
|
||||
hostname: "example.test",
|
||||
username: "alice",
|
||||
command: "true",
|
||||
authMethod: "auto",
|
||||
password: "fallback-password",
|
||||
enableKeyboardInteractive: true,
|
||||
timeout: 10,
|
||||
},
|
||||
),
|
||||
/stop after options capture/,
|
||||
);
|
||||
|
||||
assert.equal(calls.agentSocketChecks, 1);
|
||||
assert.equal(calls.authConfig.sshAgentSocketOverride, null);
|
||||
});
|
||||
|
||||
for (const identitiesOnly of [true, false]) {
|
||||
test(`execCommand uses the system agent without reading private keys (identitiesOnly=${identitiesOnly})`, async () => {
|
||||
const { api, calls, preparedAgent } = createHarness({ identitiesOnly });
|
||||
|
||||
await assert.rejects(
|
||||
() => api.execCommand(
|
||||
{ sender: {} },
|
||||
{
|
||||
hostname: "example.test",
|
||||
username: "alice",
|
||||
command: "true",
|
||||
privateKey: "encrypted-inline-key",
|
||||
identityFilePaths: ["/keys/encrypted-key"],
|
||||
useSshAgent: true,
|
||||
identitiesOnly,
|
||||
enableKeyboardInteractive: true,
|
||||
timeout: 10,
|
||||
},
|
||||
),
|
||||
/stop after options capture/,
|
||||
);
|
||||
|
||||
assert.equal(calls.inlineKeyLoads, 0);
|
||||
assert.equal(calls.identityFileLoads, 0);
|
||||
assert.equal(calls.defaultKeyScans, identitiesOnly ? 0 : 1);
|
||||
assert.equal(calls.authConfig.agent, preparedAgent);
|
||||
assert.deepEqual(calls.authConfig.defaultKeys, identitiesOnly ? [] : [{ privateKey: "default-key" }]);
|
||||
assert.equal(calls.connectOptions.agent, preparedAgent);
|
||||
assert.deepEqual(calls.connectOptions.authHandler, ["agent"]);
|
||||
assert.equal(calls.endCount, 1);
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user