feat: capture SSH exec commands (PLAN.md 4.4)
Bots often send commands via `ssh user@host <command>` (exec request) rather than requesting an interactive shell. These were previously rejected silently. Now exec commands are captured, stored on the session record, and displayed in the web UI session detail page. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -361,6 +361,69 @@ func TestCloseActiveSessions(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestSetExecCommand(t *testing.T) {
|
||||
testStores(t, func(t *testing.T, newStore storeFactory) {
|
||||
t.Run("set and retrieve", func(t *testing.T) {
|
||||
store := newStore(t)
|
||||
ctx := context.Background()
|
||||
|
||||
id, err := store.CreateSession(ctx, "10.0.0.1", "root", "bash", "")
|
||||
if err != nil {
|
||||
t.Fatalf("CreateSession: %v", err)
|
||||
}
|
||||
|
||||
// Initially nil.
|
||||
s, err := store.GetSession(ctx, id)
|
||||
if err != nil {
|
||||
t.Fatalf("GetSession: %v", err)
|
||||
}
|
||||
if s.ExecCommand != nil {
|
||||
t.Errorf("expected nil ExecCommand, got %q", *s.ExecCommand)
|
||||
}
|
||||
|
||||
// Set exec command.
|
||||
if err := store.SetExecCommand(ctx, id, "uname -a"); err != nil {
|
||||
t.Fatalf("SetExecCommand: %v", err)
|
||||
}
|
||||
|
||||
s, err = store.GetSession(ctx, id)
|
||||
if err != nil {
|
||||
t.Fatalf("GetSession: %v", err)
|
||||
}
|
||||
if s.ExecCommand == nil {
|
||||
t.Fatal("expected non-nil ExecCommand")
|
||||
}
|
||||
if *s.ExecCommand != "uname -a" {
|
||||
t.Errorf("ExecCommand = %q, want %q", *s.ExecCommand, "uname -a")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("appears in recent sessions", func(t *testing.T) {
|
||||
store := newStore(t)
|
||||
ctx := context.Background()
|
||||
|
||||
id, err := store.CreateSession(ctx, "10.0.0.1", "root", "bash", "")
|
||||
if err != nil {
|
||||
t.Fatalf("CreateSession: %v", err)
|
||||
}
|
||||
if err := store.SetExecCommand(ctx, id, "id"); err != nil {
|
||||
t.Fatalf("SetExecCommand: %v", err)
|
||||
}
|
||||
|
||||
sessions, err := store.GetRecentSessions(ctx, 10, false)
|
||||
if err != nil {
|
||||
t.Fatalf("GetRecentSessions: %v", err)
|
||||
}
|
||||
if len(sessions) != 1 {
|
||||
t.Fatalf("len = %d, want 1", len(sessions))
|
||||
}
|
||||
if sessions[0].ExecCommand == nil || *sessions[0].ExecCommand != "id" {
|
||||
t.Errorf("ExecCommand = %v, want \"id\"", sessions[0].ExecCommand)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func TestGetRecentSessions(t *testing.T) {
|
||||
testStores(t, func(t *testing.T, newStore storeFactory) {
|
||||
t.Run("empty", func(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user