diff --git a/cmd/dash.go b/cmd/dash.go index 415f908..95e3817 100644 --- a/cmd/dash.go +++ b/cmd/dash.go @@ -90,8 +90,9 @@ type dashModel struct { interval time.Duration self string // path to this binary, for re-invoking subcommands - auth checks.AuthStatus - docker dockerMsg + auth checks.AuthStatus + authChecked bool // true once the first auth result has arrived + docker dockerMsg drift driftMsg repos repoMsg @@ -325,6 +326,7 @@ func (m dashModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { } case authMsg: m.auth = checks.AuthStatus(msg) + m.authChecked = true m.lastRefresh = time.Now() case dockerMsg: m.docker = msg @@ -582,17 +584,23 @@ func (m dashModel) footer() string { func (m dashModel) authPanel() string { var s strings.Builder s.WriteString(headerStyle.Render("AWS AUTH") + "\n") - if m.auth.Authed { + switch { + case !m.authChecked: + s.WriteString(dimStyle.Render("checking…")) + case m.auth.Authed: mark := okStyle.Render("✓ authed") // Warn when the session expires within 30 min. if !m.auth.Expires.IsZero() && time.Until(m.auth.Expires) < 30*time.Minute { mark = badStyle.Render("⚠ expiring") } s.WriteString(mark + dimStyle.Render(" "+m.auth.Detail)) - } else if m.auth.Err != "" { - s.WriteString(badStyle.Render("✗ re-auth needed") + "\n" + dimStyle.Render(truncate(m.auth.Err, 70))) - } else { - s.WriteString(dimStyle.Render("checking…")) + default: + // Not authed: awsmfa errored, or the session is gone/expired. + detail := m.auth.Err + if detail == "" { + detail = m.auth.Detail + } + s.WriteString(badStyle.Render("✗ re-auth needed") + "\n" + dimStyle.Render(truncate(detail, 70))) } return s.String() } diff --git a/cmd/dash_render_test.go b/cmd/dash_render_test.go index 5fbcf55..ce36ba8 100644 --- a/cmd/dash_render_test.go +++ b/cmd/dash_render_test.go @@ -38,6 +38,26 @@ func TestDashViewRenders(t *testing.T) { } } +func TestAuthPanelExpiredShowsReauth(t *testing.T) { + m := newDash([]string{"/tmp"}, "/x/awsmfa", "", 10*time.Second) + + // Before any check result has arrived, the panel shows the spinner. + if !strings.Contains(m.View(), "checking…") { + t.Errorf("initial panel should show checking…\n---\n%s", m.authPanel()) + } + + // Expired session: awsmfa printed "Not authenticated." → Authed false, Err empty. + um, _ := m.Update(authMsg(checks.AuthStatus{Authed: false, Detail: "Not authenticated."})) + m = um.(dashModel) + got := m.authPanel() + if strings.Contains(got, "checking…") { + t.Errorf("expired session still shows checking…\n---\n%s", got) + } + if !strings.Contains(got, "re-auth needed") { + t.Errorf("expired session should show re-auth needed\n---\n%s", got) + } +} + func names(items []suggestion) string { var b strings.Builder for _, it := range items {