feat: add session indicators and top exec commands to dashboard
Add visual indicators to session tables (replay badge when events exist, exec badge for exec sessions) and a new "Top Exec Commands" table on the dashboard. Includes EventCount field on Session, GetTopExecCommands on Store interface, and truncateCommand template function. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -204,6 +204,79 @@ func TestDeleteRecordsBefore(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetTopExecCommands(t *testing.T) {
|
||||
store := newTestStore(t)
|
||||
ctx := context.Background()
|
||||
|
||||
// Create sessions with exec commands.
|
||||
for range 3 {
|
||||
id, err := store.CreateSession(ctx, "10.0.0.1", "root", "", "")
|
||||
if err != nil {
|
||||
t.Fatalf("creating session: %v", err)
|
||||
}
|
||||
if err := store.SetExecCommand(ctx, id, "uname -a"); err != nil {
|
||||
t.Fatalf("setting exec command: %v", err)
|
||||
}
|
||||
}
|
||||
for range 2 {
|
||||
id, err := store.CreateSession(ctx, "10.0.0.2", "admin", "", "")
|
||||
if err != nil {
|
||||
t.Fatalf("creating session: %v", err)
|
||||
}
|
||||
if err := store.SetExecCommand(ctx, id, "cat /etc/passwd"); err != nil {
|
||||
t.Fatalf("setting exec command: %v", err)
|
||||
}
|
||||
}
|
||||
// Session without exec command — should not appear.
|
||||
if _, err := store.CreateSession(ctx, "10.0.0.3", "test", "bash", ""); err != nil {
|
||||
t.Fatalf("creating session: %v", err)
|
||||
}
|
||||
|
||||
entries, err := store.GetTopExecCommands(ctx, 10)
|
||||
if err != nil {
|
||||
t.Fatalf("GetTopExecCommands: %v", err)
|
||||
}
|
||||
if len(entries) != 2 {
|
||||
t.Fatalf("len = %d, want 2", len(entries))
|
||||
}
|
||||
if entries[0].Value != "uname -a" || entries[0].Count != 3 {
|
||||
t.Errorf("entries[0] = %+v, want uname -a:3", entries[0])
|
||||
}
|
||||
if entries[1].Value != "cat /etc/passwd" || entries[1].Count != 2 {
|
||||
t.Errorf("entries[1] = %+v, want cat /etc/passwd:2", entries[1])
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetRecentSessionsEventCount(t *testing.T) {
|
||||
store := newTestStore(t)
|
||||
ctx := context.Background()
|
||||
|
||||
id, err := store.CreateSession(ctx, "10.0.0.1", "root", "bash", "")
|
||||
if err != nil {
|
||||
t.Fatalf("creating session: %v", err)
|
||||
}
|
||||
|
||||
// Add some events.
|
||||
events := []SessionEvent{
|
||||
{SessionID: id, Timestamp: time.Now(), Direction: 0, Data: []byte("ls\n")},
|
||||
{SessionID: id, Timestamp: time.Now(), Direction: 1, Data: []byte("file1\n")},
|
||||
}
|
||||
if err := store.AppendSessionEvents(ctx, events); err != nil {
|
||||
t.Fatalf("appending events: %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].EventCount != 2 {
|
||||
t.Errorf("EventCount = %d, want 2", sessions[0].EventCount)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewSQLiteStoreCreatesFile(t *testing.T) {
|
||||
dbPath := filepath.Join(t.TempDir(), "test.db")
|
||||
store, err := NewSQLiteStore(dbPath)
|
||||
|
||||
Reference in New Issue
Block a user