From 4111d4be4b51041191547ad0b8631e3f5e83ac1f Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Sun, 5 Apr 2026 03:15:20 +0000 Subject: [PATCH] ssh/tailssh: fix integration test hang due to missing host keys Commit f905871fb moved host key generation from the ipnLocalBackend interface (GetSSH_HostKeys) to the standalone getHostKeys function, which requires either system host keys in /etc/ssh/ or a valid TailscaleVarRoot to generate keys into. The testBackend returned "" for TailscaleVarRoot, and the Docker test containers only install openssh-client (no server host keys), so getHostKeys always failed. When getHostKeys fails, HandleSSHConn returns the error but never closes the TCP connection, so SSH clients hang forever waiting for the server hello. Fix by creating a temp directory in TestMain and returning it from testBackend.TailscaleVarRoot(). Regression from f905871fb #18949 ("ipn/ipnlocal, feature/ssh: move SSH code out of LocalBackend to feature"). I was apparently too impatient to wait for the test to complete and didn't connect the dots: https://github.com/tailscale/tailscale/actions/runs/22930275950 We should make that test faster (#19244) for the patience issue, but also fail more nicely if this happens in the future. Updates #19244 Change-Id: If82393b8f35413b04174e6f7d09a1ee3a2125a6b Signed-off-by: Brad Fitzpatrick --- ssh/tailssh/tailssh_integration_test.go | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/ssh/tailssh/tailssh_integration_test.go b/ssh/tailssh/tailssh_integration_test.go index ea2fe8577..1eb79b37e 100644 --- a/ssh/tailssh/tailssh_integration_test.go +++ b/ssh/tailssh/tailssh_integration_test.go @@ -52,7 +52,21 @@ import ( // - User "testuser" exists // - "testuser" is in groups "groupone" and "grouptwo" +// testVarRoot is a temp directory used as the TailscaleVarRoot for +// host key generation during integration tests. The test containers +// don't have system host keys (/etc/ssh/ssh_host_*_key) since they +// only install openssh-client, so getHostKeys needs a valid var root +// to generate keys into. +var testVarRoot string + func TestMain(m *testing.M) { + var err error + testVarRoot, err = os.MkdirTemp("", "tailssh-test-var") + if err != nil { + log.Fatal(err) + } + defer os.RemoveAll(testVarRoot) + // Create our log file. file, err := os.OpenFile("/tmp/tailscalessh.log", os.O_CREATE|os.O_WRONLY, 0666) if err != nil { @@ -672,7 +686,7 @@ func (tb *testBackend) Dialer() *tsdial.Dialer { } func (tb *testBackend) TailscaleVarRoot() string { - return "" + return testVarRoot } func (tb *testBackend) NodeKey() key.NodePublic {