From cea2442c4f20eb80755f68fc20f4a61388a795d9 Mon Sep 17 00:00:00 2001 From: root Date: Thu, 4 Jun 2026 22:00:52 +1000 Subject: [PATCH] fix(actions): ssh channel pins known_hosts beside key (no HOME dependency) Co-Authored-By: Claude Opus 4.8 --- lib/actions/channels/ssh.js | 6 +++++- tests/actions/ssh.test.js | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/actions/channels/ssh.js b/lib/actions/channels/ssh.js index b252143..cc799d7 100644 --- a/lib/actions/channels/ssh.js +++ b/lib/actions/channels/ssh.js @@ -1,4 +1,5 @@ import { spawn as nodeSpawn } from 'node:child_process'; +import { dirname, join } from 'node:path'; const ID_RE = /^[a-z0-9-]+$/; @@ -11,8 +12,11 @@ export function restartService({ ip, actionId }, { spawnImpl = nodeSpawn } = {}) { if (!ID_RE.test(actionId || '')) return Promise.reject(new Error(`invalid action id: ${actionId}`)); + // Pin known_hosts beside the key (writable, void-owned) so the channel doesn't + // depend on the service's HOME for ~/.ssh. + const knownHosts = join(dirname(keyPath), 'known_hosts'); const args = ['-i', keyPath, '-o', 'BatchMode=yes', '-o', 'StrictHostKeyChecking=accept-new', - `${user}@${ip}`, actionId]; + '-o', `UserKnownHostsFile=${knownHosts}`, `${user}@${ip}`, actionId]; return new Promise((resolve, reject) => { const child = spawnImpl('ssh', args); let out = '', err = ''; diff --git a/tests/actions/ssh.test.js b/tests/actions/ssh.test.js index c3d74c3..7e780d2 100644 --- a/tests/actions/ssh.test.js +++ b/tests/actions/ssh.test.js @@ -15,7 +15,7 @@ describe('ssh channel', () => { const { cmd, args } = calls[0]; expect(cmd).toBe('ssh'); expect(args).toEqual(['-i', '/k', '-o', 'BatchMode=yes', '-o', 'StrictHostKeyChecking=accept-new', - 'voidact@192.168.1.230', 'restart-caddy-ct100']); + '-o', 'UserKnownHostsFile=/known_hosts', 'voidact@192.168.1.230', 'restart-caddy-ct100']); }); it('rejects an action id with shell metacharacters', async () => { await expect(restartService({ ip: '1.2.3.4', actionId: 'x; rm -rf /' }, { spawnImpl: () => {} }))