fix: support Tailscale auth in tmux monitor (#1113)

This commit is contained in:
ZacharyZcR
2026-07-28 01:48:31 +08:00
committed by GitHub
parent 3f33961657
commit 8743e6daa2
3 changed files with 40 additions and 2 deletions
+11
View File
@@ -0,0 +1,11 @@
import type { SSHHost } from "../../../types/index.js";
export function getTmuxAuthBehavior(authType: SSHHost["authType"]): {
credentialless: boolean;
tryKeyboard: boolean;
} {
return {
credentialless: authType === "none" || authType === "tailscale",
tryKeyboard: authType !== "tailscale",
};
}
+4 -2
View File
@@ -40,6 +40,7 @@ import {
type PaneMetrics,
} from "./monitor-helpers.js";
import type { SSHHost, AuthenticatedRequest } from "../../../types/index.js";
import { getTmuxAuthBehavior } from "./auth-utils.js";
const PANE_ID_RE = /^%\d+$/;
// tmux session names cannot contain ":" or "."; keep to a conservative
@@ -59,11 +60,12 @@ interface TmuxSessionOverview extends TmuxSessionSummary {
// and docker; jump hosts and SOCKS5 reuse the shared helpers)
async function buildSshConfig(host: SSHHost): Promise<ConnectConfig> {
const authBehavior = getTmuxAuthBehavior(host.authType);
const base: ConnectConfig = {
host: (host.ip || "").replace(/^\[|\]$/g, ""),
port: host.port,
username: host.username,
tryKeyboard: true,
tryKeyboard: authBehavior.tryKeyboard,
keepaliveInterval: 30000,
keepaliveCountMax: 3,
readyTimeout: 60000,
@@ -94,7 +96,7 @@ async function buildSshConfig(host: SSHHost): Promise<ConnectConfig> {
if (host.keyPassword) {
(base as Record<string, unknown>).passphrase = host.keyPassword;
}
} else if (host.authType === "none") {
} else if (authBehavior.credentialless) {
// no credentials needed
} else if (host.authType === "vault") {
// cert auth setup happens in connectToHost (needs client instance)
@@ -0,0 +1,25 @@
import { describe, expect, it } from "vitest";
import { getTmuxAuthBehavior } from "../../../hosts/tmux/auth-utils.js";
describe("getTmuxAuthBehavior", () => {
it("uses credentialless non-interactive authentication for Tailscale SSH", () => {
expect(getTmuxAuthBehavior("tailscale")).toEqual({
credentialless: true,
tryKeyboard: false,
});
});
it("preserves keyboard-interactive fallback for none authentication", () => {
expect(getTmuxAuthBehavior("none")).toEqual({
credentialless: true,
tryKeyboard: true,
});
});
it("does not treat password authentication as credentialless", () => {
expect(getTmuxAuthBehavior("password")).toEqual({
credentialless: false,
tryKeyboard: true,
});
});
});