package cli import ( "encoding/json" "strings" "testing" ) // With only EMCLI_KEY set, `account list` emits the reduced JSON envelope: // name/from/can_send, and never the IMAP host or login username. func TestAccountListAgentJSONView(t *testing.T) { adminEnv(t) // both keys + initialized temp DB run(t, "account", "add", "--name", "work", "--mode", "RW", "--imap-host", "imap.example.com", "--smtp-host", "smtp.example.com", "--username", "login@example.com", "--from", "me@example.com") run(t, "account", "add", "--name", "alerts", "--mode", "RO", "--imap-host", "imap.example.com", "--username", "alerts@example.com") // Drop the admin key → caller is an agent. t.Setenv("EMCLI_ADMIN_KEY", "") code, out, errOut := run(t, "account", "list") if code != 0 { t.Fatalf("agent account list should succeed: code=%d err=%q", code, errOut) } var env struct { Error bool `json:"error"` Data struct { Accounts []struct { Name string `json:"name"` From string `json:"from"` CanSend bool `json:"can_send"` } `json:"accounts"` } `json:"data"` } if err := json.Unmarshal([]byte(out), &env); err != nil { t.Fatalf("output is not the agent envelope: %v\n%s", err, out) } if env.Error || len(env.Data.Accounts) != 2 { t.Fatalf("want 2 accounts and no error, got %+v", env) } // The reduced view must not leak the IMAP host or the login username. if strings.Contains(out, "imap.example.com") || strings.Contains(out, "login@example.com") { t.Fatalf("agent view leaked host/username:\n%s", out) } got := map[string]struct { from string canSend bool }{} for _, a := range env.Data.Accounts { got[a.Name] = struct { from string canSend bool }{a.From, a.CanSend} } if g := got["work"]; g.from != "me@example.com" || !g.canSend { t.Errorf("work: want from=me@example.com can_send=true, got %+v", g) } // alerts has no --from → SendFrom() falls back to the username. if g := got["alerts"]; g.from != "alerts@example.com" || g.canSend { t.Errorf("alerts: want from=alerts@example.com can_send=false, got %+v", g) } } // With the admin key present, `account list` stays the full human-readable table. func TestAccountListAdminTextView(t *testing.T) { adminEnv(t) run(t, "account", "add", "--name", "work", "--mode", "RW", "--imap-host", "imap.example.com", "--smtp-host", "smtp.example.com", "--username", "login@example.com", "--from", "me@example.com") code, out, _ := run(t, "account", "list") if code != 0 { t.Fatalf("admin account list failed: code=%d", code) } for _, want := range []string{"NAME", "MODE", "IMAP", "USER", "imap.example.com:993", "login@example.com"} { if !strings.Contains(out, want) { t.Fatalf("admin view missing %q:\n%s", want, out) } } if strings.Contains(out, `"accounts"`) { t.Fatalf("admin view should be text, not JSON:\n%s", out) } }