provider: removing the account a subscription uses first puts the next one first, and Sign out… takes every account (歧路亡羊 on Discord) — Copilot's Sign out… stopped at "magpie uses wwjxhy first; put another account first" and kept the account
This commit is contained in:
1 parent
9fb51c7742
commit
30d952cf0c
5 files changed
+71
-29
No files matched your search
@@ -2,7 +2,7 @@ package provider
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@@ -34,15 +34,23 @@ func TestForgetOnlyFirstLogin(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// two accounts: Remove on the first still asks for the other first,
|
||||
// and signing the subscription out takes both
|
||||
// two accounts: Remove on the first puts the other first, even one
|
||||
// that was off, and signing the subscription out takes both
|
||||
saveLogins(t,
|
||||
savedLogin{Agent: "antigravity", User: "a@x.com", Auth: auth("ra"), On: true, First: true},
|
||||
savedLogin{Agent: "antigravity", User: "b@x.com", Auth: auth("rb")})
|
||||
ForgetAccounts()
|
||||
if err := ForgetLogin("antigravity", "a@x.com"); err != nil {
|
||||
t.Fatalf("removing the first of two: %v", err)
|
||||
}
|
||||
ForgetAccounts()
|
||||
if ls := Logins("antigravity"); len(ls) != 1 || ls[0].User != "b@x.com" || !ls[0].Active || !ls[0].On {
|
||||
t.Fatalf("after removing the first: %+v", ls)
|
||||
}
|
||||
saveLogins(t,
|
||||
savedLogin{Agent: "antigravity", User: "a@x.com", Auth: auth("ra"), On: true, First: true},
|
||||
savedLogin{Agent: "antigravity", User: "b@x.com", Auth: auth("rb"), On: true})
|
||||
ForgetAccounts()
|
||||
if err := ForgetLogin("antigravity", "a@x.com"); err == nil || !strings.Contains(err.Error(), "put another account first") {
|
||||
t.Fatalf("removing the first of two: %v", err)
|
||||
}
|
||||
if err := ForgetAccount("antigravity"); err != nil {
|
||||
t.Fatalf("signing out both: %v", err)
|
||||
}
|
||||
@@ -51,3 +59,41 @@ func TestForgetOnlyFirstLogin(t *testing.T) {
|
||||
t.Fatalf("still listed: %+v", ls)
|
||||
}
|
||||
}
|
||||
|
||||
// 歧路亡羊 on Discord: Copilot signed in to the editors' own account and
|
||||
// two of magpie's, one of them first. Removing the first puts the next
|
||||
// first, and Sign out… takes them all, where it said "magpie uses wwjxhy
|
||||
// first; put another account first".
|
||||
func TestForgetFirstCopilotLogin(t *testing.T) {
|
||||
signIn(t)
|
||||
writeFile(t, filepath.Join(copilotConfigDir(), "github-copilot", "apps.json"), map[string]any{"github.com": map[string]any{"user": "octo", "oauth_token": "gho_own"}})
|
||||
tok := func(s string) json.RawMessage { return json.RawMessage(`{"oauth_token":"` + s + `"}`) }
|
||||
saved := []savedLogin{
|
||||
{Agent: "copilot", User: "octo"},
|
||||
{Agent: "copilot", User: "wwjxhy", Auth: tok("gho_w"), On: true, First: true},
|
||||
{Agent: "copilot", User: "other", Auth: tok("gho_o"), On: true},
|
||||
}
|
||||
saveLogins(t, saved...)
|
||||
ForgetAccounts()
|
||||
if ls := Logins("copilot"); len(ls) != 3 || ls[0].User != "wwjxhy" || !ls[0].Active {
|
||||
t.Fatalf("logins before: %+v", ls)
|
||||
}
|
||||
if err := ForgetLogin("copilot", "wwjxhy"); err != nil {
|
||||
t.Fatalf("removing the first: %v", err)
|
||||
}
|
||||
ForgetAccounts()
|
||||
ls := Logins("copilot")
|
||||
if len(ls) != 2 || !ls[0].Active || ls[0].User == "wwjxhy" || ls[1].User == "wwjxhy" {
|
||||
t.Fatalf("after removing the first: %+v", ls)
|
||||
}
|
||||
|
||||
saveLogins(t, saved...)
|
||||
ForgetAccounts()
|
||||
if err := forgetLogins("copilot"); err != nil {
|
||||
t.Fatalf("signing out every account: %v", err)
|
||||
}
|
||||
ForgetAccounts()
|
||||
if ls := Logins("copilot"); len(ls) != 0 {
|
||||
t.Fatalf("still listed: %+v", ls)
|
||||
}
|
||||
}
|
||||
@@ -120,9 +120,6 @@ func TestGrokAccounts(t *testing.T) {
|
||||
if b, _ := os.ReadFile(filepath.Join(own, "auth.json")); len(b) == 0 {
|
||||
t.Fatal("the CLI's own sign-in was touched")
|
||||
}
|
||||
if err := ForgetLogin("grok", "two@x.ai"); err == nil {
|
||||
t.Fatal("forgot the account in use first")
|
||||
}
|
||||
if err := SetLoginOn("grok", "me@x.ai", false); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -173,13 +173,17 @@ func TestKiroSeveralAccounts(t *testing.T) {
|
||||
home = l.Home
|
||||
}
|
||||
}
|
||||
if err := ForgetLogin("kiro", "two@example.com"); err == nil {
|
||||
t.Fatal("forgot the account in use first")
|
||||
// the first removed, the next is put first
|
||||
if err := ForgetLogin("kiro", "two@example.com"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if ls := Logins("kiro"); len(ls) != 1 || ls[0].User != "me@example.com" || !ls[0].Active {
|
||||
t.Fatalf("after removing the first: %+v", ls)
|
||||
}
|
||||
if err := ForgetLogin("kiro", "me@example.com"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := os.Stat(home); !os.IsNotExist(err) || len(Logins("kiro")) != 1 {
|
||||
if _, err := os.Stat(home); !os.IsNotExist(err) || len(Logins("kiro")) != 0 {
|
||||
t.Fatalf("home %s left: %v, %+v", home, err, Logins("kiro"))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,9 +192,6 @@ func TestPluginAccounts(t *testing.T) {
|
||||
if a := also(); len(a) != 1 || a[0] != "blue@fake@fakeco" {
|
||||
t.Fatalf("also on %v", a)
|
||||
}
|
||||
if err := ForgetLogin("fakeco", "red@fake"); err == nil {
|
||||
t.Fatal("the first account was removed")
|
||||
}
|
||||
if err := ForgetLogin("fakeco", "blue@fake"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -168,12 +168,12 @@ func setSideLoginOn(agent, user string, on bool, ls []sideLogin) error {
|
||||
|
||||
// forgetSideLogin drops an account magpie signed in; gone is told what it
|
||||
// kept. The agent's own sign-in is only hidden: its files stay as they
|
||||
// are, and it shows again once the agent signs in anew (ownMark). Hidden
|
||||
// while first, the next account is put first. One of magpie's that is
|
||||
// first waits for another to be put first, unless it is the only one: then
|
||||
// there is none to put first, and it goes, leaving the subscription with no
|
||||
// account (#874: a removed subscription's Sign out… could never take its
|
||||
// one account).
|
||||
// are, and it shows again once the agent signs in anew (ownMark). Either
|
||||
// one, removed while first, puts the next account first; the only one
|
||||
// leaves the subscription with no account (#874: a removed subscription's
|
||||
// Sign out… could never take its one account; 歧路亡羊 on Discord: one of
|
||||
// magpie's that was first was refused, "put another account first", even
|
||||
// by the subscription's Sign out…, which takes every account).
|
||||
func forgetSideLogin(agent, user string, ls []sideLogin, gone func(savedLogin)) error {
|
||||
own := slices.ContainsFunc(ls, func(l sideLogin) bool { return l.Own && strings.EqualFold(l.User, user) })
|
||||
first := strings.EqualFold(activeOf(ls), user)
|
||||
@@ -186,22 +186,20 @@ func forgetSideLogin(agent, user string, ls []sideLogin, gone func(savedLogin))
|
||||
}
|
||||
}
|
||||
}
|
||||
if first && !own && next != "" {
|
||||
return fmt.Errorf("magpie uses %s first; put another account first", user)
|
||||
}
|
||||
mark := hiddenNoMark
|
||||
if own {
|
||||
mark = firstNonEmpty(ownMark(agent), hiddenNoMark)
|
||||
}
|
||||
var old savedLogin
|
||||
err := editSideLogin(agent, user, func(saved []savedLogin, i int) ([]savedLogin, error) {
|
||||
for j := range saved {
|
||||
if next != "" && j != i && saved[j].Agent == agent {
|
||||
saved[j].First = strings.EqualFold(saved[j].User, next)
|
||||
saved[j].On = saved[j].On || saved[j].First
|
||||
}
|
||||
}
|
||||
if saved[i].own() {
|
||||
saved[i].Hidden, saved[i].First = mark, false
|
||||
for j := range saved {
|
||||
if next != "" && saved[j].Agent == agent {
|
||||
saved[j].First = strings.EqualFold(saved[j].User, next)
|
||||
}
|
||||
}
|
||||
return saved, nil
|
||||
}
|
||||
old = saved[i]
|
||||
|
||||
Reference in new issue
Block a user