# auth: remove unused RemoveAllContexts

`74c24b2`·

toothbrush·1mo ago·2 files·+0 added/-80 removed

Dead since `logout --all` was redefined to revoke server-side sessions rather than nuke all local contexts. Nothing else references it.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

## Sessions

7dc263eaaac8View transcript

## Changes

2

- cmd/entire/cli/auth

- Mcontext_store.go-29
  
  - Mcontexts_test.go-51

```
61 unmodified lines

return nil
}

// RemoveAllContexts deletes every stored context and its keyring token — a
// full local logout. Returns the number of contexts removed. Best-effort on
the keyring deletes; the contexts.json clear is what makes the CLI fully
logged out.
func RemoveAllContexts() (int, error) {
	var removed int
	if err := contexts.Modify(contexts.DefaultConfigDir(), func(f *contexts.File) (bool, error) {
		if len(f.Contexts) == 0 && f.CurrentContext == "" {
			return false, nil
		}
		for _, c := range f.Contexts {
			if c.KeychainService != "" && c.Handle != "" {
				// Delete both slots: the access token and its paired refresh
				// token. Dropping the refresh slot is what actually scrubs the
				// machine — otherwise a leftover refresh token outlives logout.
				_ = tokenstore.Delete(c.KeychainService, c.Handle)                            //nolint:errcheck // best-effort; the contexts.json clear below is authoritative
				_ = tokenstore.Delete(tokenstore.RefreshService(c.KeychainService), c.Handle) //nolint:errcheck // best-effort; absent refresh slot is fine
			}
			removed++
		}
		f.Contexts = nil
		f.CurrentContext = ""
		return true, nil
	}); err != nil {
		return 0, fmt.Errorf("remove all contexts: %w", err)
	}
	return removed, nil
}

// SetCurrentContext makes name the active context. Returns an error when
// no context with that name exists (a stale current pointer is a foot-gun).
func SetCurrentContext(name string) error {
```

Mcmd/entire/cli/auth/context_store.go-29

```
268 unmodified lines

func TestRemoveAllContexts(t *testing.T) {
	cfgDir := t.TempDir()
	t.Setenv("ENTIRE_CONFIG_DIR", cfgDir)
	restore := tokenstore.UseFileBackendForTesting(filepath.Join(t.TempDir(), "tokens.json"))
	t.Cleanup(restore)

exp := time.Now().Add(time.Hour).Unix()
	if _, err := RecordLoginContext(makeJWT(t, fmt.Sprintf(`{"iss":"https://a.example.com","handle":"alice","exp":%d}`, exp)), "entr_a", true); err != nil {
		t.Fatalf("record a: %v", err)
	}
	if _, err := RecordLoginContext(makeJWT(t, fmt.Sprintf(`{"iss":"https://b.example.com","handle":"bob","exp":%d}`, exp)), "entr_b", true); err != nil {
		t.Fatalf("record b: %v", err)
	}
	n, err := RemoveAllContexts()
	if err != nil {
		t.Fatalf("RemoveAllContexts: %v", err)
	}
	if n != 2 {
		t.Fatalf("removed %d, want 2", n)
	}
	f, err := contexts.Load(cfgDir)
	if err != nil {
		t.Fatalf("load: %v", err)
	}
	if len(f.Contexts) != 0 || f.CurrentContext != "" {
		t.Fatalf("expected fully cleared, got contexts=%d current=%q", len(f.Contexts), f.CurrentContext)
	}
	// Every refresh slot must be gone too, for both removed contexts.
	for _, tc := range []struct{ iss, handle string }{
		{"https://a.example.com", "alice"},
		{"https://b.example.com", "bob"},
	} {
		svc := tokenstore.CoreKeyringService(tc.iss)
		if v, err := tokenstore.Get(svc, tc.handle); !errors.Is(err, tokenstore.ErrNotFound) {
			t.Fatalf("access slot for %s survived: value=%q err=%v", tc.handle, v, err)
		}
		if v, err := tokenstore.Get(tokenstore.RefreshService(svc), tc.handle); !errors.Is(err, tokenstore.ErrNotFound) {
			t.Fatalf("refresh slot for %s survived: value=%q err=%v", tc.handle, v, err)
		}
	}

// Idempotent.
	n2, err := RemoveAllContexts()
	if err != nil {
		t.Fatalf("second RemoveAllContexts: %v", err)
	}
	if n2 != 0 {
		t.Fatalf("second call removed %d, want 0", n2)
	}
}

func TestRemoveCurrentContext_DoesNotSwitchToAnother(t *testing.T) {
	cfgDir := t.TempDir()
	t.Setenv("ENTIRE_CONFIG_DIR", cfgDir)
