Skip to content

Commit 36e724a

Browse files
committed
chore: update X11 forward session usage when there is a connection
1 parent b9c8109 commit 36e724a

File tree

2 files changed

+53
-8
lines changed

2 files changed

+53
-8
lines changed

agent/agentssh/x11.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,11 @@ func (x *x11Forwarder) listenForConnections(
162162
x.logger.Warn(ctx, "failed to accept X11 connection", slog.Error(err))
163163
return
164164
}
165+
166+
// Update session usage time since a new X11 connection was forwarded.
167+
x.mu.Lock()
168+
session.usedAt = time.Now()
169+
x.mu.Unlock()
165170
if x11.SingleConnection {
166171
x.logger.Debug(ctx, "single connection requested, closing X11 listener")
167172
x.closeAndRemoveSession(session)

agent/agentssh/x11_test.go

Lines changed: 48 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -234,8 +234,31 @@ func TestServer_X11_EvictionLRU(t *testing.T) {
234234
})
235235
}
236236

237-
// Create one more session which should evict the first (LRU) session and
238-
// therefore reuse the very first display/port.
237+
// Connect X11 forwarding to the first session. This is used to test that
238+
// connecting counts as a use of the display.
239+
x11Chans := c.HandleChannelOpen("x11")
240+
payload := "hello world"
241+
go func() {
242+
conn, err := inproc.Dial(ctx, testutil.NewAddr("tcp", fmt.Sprintf("localhost:%d", agentssh.X11StartPort+agentssh.X11DefaultDisplayOffset)))
243+
assert.NoError(t, err)
244+
_, err = conn.Write([]byte(payload))
245+
assert.NoError(t, err)
246+
_ = conn.Close()
247+
}()
248+
249+
x11 := testutil.RequireReceive(ctx, t, x11Chans)
250+
ch, reqs, err := x11.Accept()
251+
require.NoError(t, err)
252+
go gossh.DiscardRequests(reqs)
253+
got := make([]byte, len(payload))
254+
_, err = ch.Read(got)
255+
require.NoError(t, err)
256+
assert.Equal(t, payload, string(got))
257+
_ = ch.Close()
258+
259+
// Create one more session which should evict a session and reuse the display.
260+
// The first session was used to connect X11 forwarding, so it should not be evicted.
261+
// Therefore, the second session should be evicted and its display reused.
239262
extraSess, err := c.NewSession()
240263
require.NoError(t, err)
241264

@@ -273,17 +296,34 @@ func TestServer_X11_EvictionLRU(t *testing.T) {
273296
require.NoError(t, sc.Err())
274297
}
275298

276-
// The display number should have wrapped around to the starting value.
277-
assert.Equal(t, agentssh.X11DefaultDisplayOffset, newDisplayNumber, "expected display number to be reused after eviction")
299+
// The display number reused should correspond to the SECOND session (display offset 12)
300+
expectedDisplay := agentssh.X11DefaultDisplayOffset + 2 // +1 was blocked port
301+
assert.Equal(t, expectedDisplay, newDisplayNumber, "second session should have been evicted and its display reused")
278302

279-
// validate that the first session was torn down.
280-
_, err = sessions[0].stdin.Write([]byte("echo DISPLAY=$DISPLAY\n"))
303+
// First session should still be alive: send cmd and read output.
304+
msgFirst := "still-alive"
305+
_, err = sessions[0].stdin.Write([]byte("echo " + msgFirst + "\n"))
306+
require.NoError(t, err)
307+
for sessions[0].scanner.Scan() {
308+
line := strings.TrimSpace(sessions[0].scanner.Text())
309+
if strings.Contains(line, msgFirst) {
310+
break
311+
}
312+
}
313+
require.NoError(t, sessions[0].scanner.Err())
314+
315+
// Second session should now be closed.
316+
_, err = sessions[1].stdin.Write([]byte("echo dead\n"))
281317
require.ErrorIs(t, err, io.EOF)
282-
err = sessions[0].sess.Wait()
318+
err = sessions[1].sess.Wait()
283319
require.Error(t, err)
284320

285321
// Cleanup.
286-
for _, sh := range sessions[1:] {
322+
for i, sh := range sessions {
323+
if i == 1 {
324+
// already closed
325+
continue
326+
}
287327
err = sh.stdin.Close()
288328
require.NoError(t, err)
289329
err = sh.sess.Wait()

0 commit comments

Comments
 (0)