From cb853f4e083011527e7433d65468f590ca101cf0 Mon Sep 17 00:00:00 2001 From: Anthony Ettinger Date: Mon, 19 Oct 2026 15:17:12 +0000 Subject: [PATCH] fix(ssh): trust ~/.ssh/known_hosts too, so hosts OpenSSH knows are not 'unknown' (v0.16.3) SshSession only read DiskPush's own known_hosts, so `diskpush fleet run` called every server OpenSSH already trusted 'not in known_hosts' unless --accept-new was passed. It now also reads ~/.ssh/known_hosts (hashed entries included) read-only; newly trusted keys are still written to DiskPush's own file. Fixes #71. Co-Authored-By: Claude Opus 5.5 --- apps/cli/package.json | 2 +- apps/desktop/package.json | 2 +- apps/web/package.json | 2 +- packages/database/package.json | 2 +- packages/fleet-core/package.json | 2 +- packages/plugin-api/package.json | 2 +- packages/plugin-dbbackup/package.json | 2 +- packages/plugin-mediaanalyzer/package.json | 2 +- packages/rsync-core/package.json | 2 +- packages/s3-core/package.json | 2 +- packages/schemas/package.json | 2 +- packages/ssh-core/package.json | 2 +- packages/ssh-core/src/session.ts | 12 +++++++++++- 13 files changed, 23 insertions(+), 13 deletions(-) diff --git a/apps/cli/package.json b/apps/cli/package.json index 8a18b0c..b5f71bb 100644 --- a/apps/cli/package.json +++ b/apps/cli/package.json @@ -1,6 +1,6 @@ { "name": "@diskpush/cli", - "version": "0.16.2", + "version": "0.16.3", "type": "module", "bin": { "diskpush": "./dist/bin.js" diff --git a/apps/desktop/package.json b/apps/desktop/package.json index 7cd25be..87cdcf3 100644 --- a/apps/desktop/package.json +++ b/apps/desktop/package.json @@ -1,6 +1,6 @@ { "name": "@diskpush/desktop", - "version": "0.16.2", + "version": "0.16.3", "private": true, "type": "module", "main": "dist-electron/main/index.js", diff --git a/apps/web/package.json b/apps/web/package.json index 03a983f..b83316e 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -1,6 +1,6 @@ { "name": "@diskpush/web", - "version": "0.16.2", + "version": "0.16.3", "private": true, "type": "module", "scripts": { diff --git a/packages/database/package.json b/packages/database/package.json index 17b5ea8..640d8ba 100644 --- a/packages/database/package.json +++ b/packages/database/package.json @@ -1,6 +1,6 @@ { "name": "@diskpush/database", - "version": "0.16.2", + "version": "0.16.3", "type": "module", "main": "./dist/index.js", "types": "./dist/index.d.ts", diff --git a/packages/fleet-core/package.json b/packages/fleet-core/package.json index a966965..79ecf59 100644 --- a/packages/fleet-core/package.json +++ b/packages/fleet-core/package.json @@ -1,6 +1,6 @@ { "name": "@diskpush/fleet-core", - "version": "0.16.2", + "version": "0.16.3", "type": "module", "main": "./dist/index.js", "types": "./dist/index.d.ts", diff --git a/packages/plugin-api/package.json b/packages/plugin-api/package.json index 5c855bc..fc708fa 100644 --- a/packages/plugin-api/package.json +++ b/packages/plugin-api/package.json @@ -1,6 +1,6 @@ { "name": "@diskpush/plugin-api", - "version": "0.16.2", + "version": "0.16.3", "type": "module", "main": "./dist/index.js", "types": "./dist/index.d.ts", diff --git a/packages/plugin-dbbackup/package.json b/packages/plugin-dbbackup/package.json index c0c0b34..f238cb6 100644 --- a/packages/plugin-dbbackup/package.json +++ b/packages/plugin-dbbackup/package.json @@ -1,6 +1,6 @@ { "name": "@diskpush/plugin-dbbackup", - "version": "0.16.2", + "version": "0.16.3", "description": "DiskPush plugin: dump Postgres, Supabase, MySQL/MariaDB and SQLite databases to tagged, verified, gzipped files, prune them, push them anywhere rsync reaches, and restore them.", "license": "MIT", "type": "module", diff --git a/packages/plugin-mediaanalyzer/package.json b/packages/plugin-mediaanalyzer/package.json index 7bc286f..726cce3 100644 --- a/packages/plugin-mediaanalyzer/package.json +++ b/packages/plugin-mediaanalyzer/package.json @@ -1,6 +1,6 @@ { "name": "@diskpush/plugin-mediaanalyzer", - "version": "0.16.2", + "version": "0.16.3", "type": "module", "main": "./dist/index.js", "types": "./dist/index.d.ts", diff --git a/packages/rsync-core/package.json b/packages/rsync-core/package.json index 5aac026..3d0b3dd 100644 --- a/packages/rsync-core/package.json +++ b/packages/rsync-core/package.json @@ -1,6 +1,6 @@ { "name": "@diskpush/rsync-core", - "version": "0.16.2", + "version": "0.16.3", "type": "module", "main": "./dist/index.js", "types": "./dist/index.d.ts", diff --git a/packages/s3-core/package.json b/packages/s3-core/package.json index e255389..8c83d3f 100644 --- a/packages/s3-core/package.json +++ b/packages/s3-core/package.json @@ -1,6 +1,6 @@ { "name": "@diskpush/s3-core", - "version": "0.16.2", + "version": "0.16.3", "type": "module", "main": "./dist/index.js", "types": "./dist/index.d.ts", diff --git a/packages/schemas/package.json b/packages/schemas/package.json index a39f0a6..d9d86b1 100644 --- a/packages/schemas/package.json +++ b/packages/schemas/package.json @@ -1,6 +1,6 @@ { "name": "@diskpush/schemas", - "version": "0.16.2", + "version": "0.16.3", "type": "module", "main": "./dist/index.js", "types": "./dist/index.d.ts", diff --git a/packages/ssh-core/package.json b/packages/ssh-core/package.json index 93a4306..1c5d4c3 100644 --- a/packages/ssh-core/package.json +++ b/packages/ssh-core/package.json @@ -1,6 +1,6 @@ { "name": "@diskpush/ssh-core", - "version": "0.16.2", + "version": "0.16.3", "type": "module", "main": "./dist/index.js", "types": "./dist/index.d.ts", diff --git a/packages/ssh-core/src/session.ts b/packages/ssh-core/src/session.ts index 9fcc007..7d4de2b 100644 --- a/packages/ssh-core/src/session.ts +++ b/packages/ssh-core/src/session.ts @@ -1,4 +1,6 @@ import { existsSync, readFileSync } from 'node:fs' +import { homedir } from 'node:os' +import { join } from 'node:path' import { Client, type AnyAuthMethod, type ConnectConfig, type SFTPWrapper } from 'ssh2' import type { Connection } from '@diskpush/schemas' import { keyTypeOf, sha256Fingerprint } from './fingerprint.js' @@ -23,7 +25,14 @@ export type HostKeyPrompt = (details: { }) => Promise export type SessionOptions = { + /** DiskPush's own known_hosts: read, and where newly trusted keys are written. */ knownHostsPath: string + /** + * Further known_hosts files trusted read-only, so a host OpenSSH already + * knows is not "new" to DiskPush. Defaults to ~/.ssh/known_hosts (hashed + * entries included); pass [] to trust only `knownHostsPath`. + */ + trustedKnownHostsPaths?: readonly string[] /** * Asked only when a host is genuinely new. A *changed* key is never * prompted away here; it fails, and the user has to deal with it @@ -76,7 +85,8 @@ export class SshSession { static async connect(connection: Connection, options: SessionOptions): Promise { const client = new Client() - const knownHosts = readKnownHosts(options.knownHostsPath) + const trusted = options.trustedKnownHostsPaths ?? [join(homedir(), '.ssh', 'known_hosts')] + const knownHosts = [options.knownHostsPath, ...trusted.filter((p) => p !== options.knownHostsPath)].flatMap(readKnownHosts) const config: ConnectConfig = { host: connection.host,