From 4399434f0cbaa954280e78b303c3d7c387cd037b Mon Sep 17 00:00:00 2001 From: Hai Huang Date: Wed, 3 Jun 2026 06:08:58 -0400 Subject: [PATCH] fix(abctl): correct pipeline divider row cell count (fixes startup panic) The inbound/outbound "(app)" divider row in the pipeline table carried 7 cells, but the table has only 6 columns (the WRITES column was removed earlier). bubbles' table.renderRow indexes columns by cell position, so it panicked ("index out of range [6] with length 6") whenever abctl rendered a pipeline. Trim the divider to 6 cells and add a regression test asserting every row matches the column count. Assisted-By: Claude (Anthropic AI) Signed-off-by: Hai Huang --- authbridge/cmd/abctl/tui/pipeline_pane.go | 7 +++- .../cmd/abctl/tui/pipeline_pane_test.go | 38 +++++++++++++++++++ 2 files changed, 43 insertions(+), 2 deletions(-) create mode 100644 authbridge/cmd/abctl/tui/pipeline_pane_test.go diff --git a/authbridge/cmd/abctl/tui/pipeline_pane.go b/authbridge/cmd/abctl/tui/pipeline_pane.go index 10c08b0a1..39d06b554 100644 --- a/authbridge/cmd/abctl/tui/pipeline_pane.go +++ b/authbridge/cmd/abctl/tui/pipeline_pane.go @@ -40,8 +40,11 @@ func (m *model) rebuildPipelineTable() { for _, p := range m.pipeline.Inbound { rows = append(rows, pipelineRow(p, counts[p.Name], m.pipeline.Inbound)) } - // Divider between inbound and outbound. - rows = append(rows, table.Row{"", "", "── (app) ──", "", "", "", ""}) + // Divider between inbound and outbound. Cell count MUST match the 6 + // columns defined in newPipelineTable (#, DIRECTION, PLUGIN, DEPS, BODY, + // EVENTS) — bubbles' table.renderRow indexes columns by cell position and + // panics on a mismatch. + rows = append(rows, table.Row{"", "", "── (app) ──", "", "", ""}) for _, p := range m.pipeline.Outbound { rows = append(rows, pipelineRow(p, counts[p.Name], m.pipeline.Outbound)) } diff --git a/authbridge/cmd/abctl/tui/pipeline_pane_test.go b/authbridge/cmd/abctl/tui/pipeline_pane_test.go new file mode 100644 index 000000000..d94c07862 --- /dev/null +++ b/authbridge/cmd/abctl/tui/pipeline_pane_test.go @@ -0,0 +1,38 @@ +package tui + +import ( + "testing" + + "github.com/kagenti/kagenti-extensions/authbridge/cmd/abctl/apiclient" +) + +// TestRebuildPipelineTable_AllRowsMatchColumnCount is a regression guard: +// every row added to the pipeline table — including the inbound/outbound +// "(app)" divider — must have exactly as many cells as the table has columns. +// The divider previously carried 7 cells against 6 columns, which made +// bubbles' table.renderRow panic ("index out of range [6] with length 6") +// the moment abctl rendered any pipeline. +func TestRebuildPipelineTable_AllRowsMatchColumnCount(t *testing.T) { + m := &model{ + pipeline: &apiclient.PipelineView{ + Inbound: []apiclient.PipelinePlugin{{Name: "jwt-validation", Direction: "inbound", Position: 1}}, + Outbound: []apiclient.PipelinePlugin{{Name: "token-exchange", Direction: "outbound", Position: 1}}, + }, + pipelineTbl: newPipelineTable(), + } + + // Must not panic: the buggy 7-cell divider panicked here via + // SetRows → UpdateViewport → renderRow. + m.rebuildPipelineTable() + + rows := m.pipelineTbl.Rows() + if len(rows) != 3 { // inbound plugin + divider + outbound plugin + t.Fatalf("rows = %d, want 3 (inbound + divider + outbound)", len(rows)) + } + const wantCells = 6 // #, DIRECTION, PLUGIN, DEPS, BODY, EVENTS + for i, r := range rows { + if len(r) != wantCells { + t.Errorf("row %d has %d cells, want %d (must match column count)", i, len(r), wantCells) + } + } +}