fix(import): require a stored token, not just a context, for logged-in check · Entire
fix(import): require a stored token, not just a context, for logged-in check
fbf2abf
Addresses Copilot's review on #1774: a contexts.json entry can exist without a usable credential (partially-removed context, missing keychain token), which made importLoggedIn suppress the sync notice even though the import can't sync. Now the current context must also yield a stored token (local read via auth.LoginTokenForContext — no network).
This stays a presence check, not a liveness check: LoginTokenForContext returns a present-but-expired token without error, and verifying usability needs a network refresh we deliberately avoid on the import path. That narrow residual false-negative (expired token) is accepted to keep the check local and prompt-free; the common broken case is now handled. Adds a test for the context-present-but-token-missing case.
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
Changes
2
cmd/entire/cli
Mimport_sync_notice.go +34/-6
- Mimport_sync_notice_test.go +53
// Local auth reads, as package vars so the login heuristic's branching is
// testable without a real keyring or config dir. Production wiring is the real
// auth functions.
var (
importListContexts = auth.Contexts
importTokenForContext = auth.LoginTokenForContext
)
// importLoggedIn reports whether there is an active login the imported history
// could eventually sync under: an ENTIRE_TOKEN env token, or a current stored
// login context. It is local-only (reads env + contexts.json) and never makes a
// network call, so it is safe on the import path. It is a package var so tests
// can force either state.
var importLoggedIn = func() bool {
if os.Getenv(auth.EnvTokenVar) != "" {
return true
}
ctxs, current, err := auth.Contexts()
return err == nil && current != "" && len(ctxs) > 0
ctxs, current, err := importListContexts()
if err != nil || current == "" {
return false
}
for _, c := range ctxs {
if c.Name == current {
tok, terr := importTokenForContext(c)
return terr == nil && tok != ""
}
}
return false
}
warnIfImportNotSynced
// warnIfImportNotSynced prints a one-time notice, when the user is not logged
TestWarnIfImportNotSynced
import (
"bytes"
"errors"
"strings"
"testing"
"github.com/entireio/cli/cmd/entire/cli/auth"
"github.com/entireio/cli/internal/entireclient/contexts"
)
func TestWarnIfImportNotSynced(t *testing.T) {
// Test implementation here
}
// TestImportLoggedIn exercises the default login heuristic's branching via the
// local-read seams.
func TestImportLoggedIn(t *testing.T) {
origCtx, origTok := importListContexts, importTokenForContext
t.Cleanup(func() { importListContexts, importTokenForContext = origCtx, origTok })
// Ensure no env token leaks in from the environment for the context cases.
t.Setenv(auth.EnvTokenVar, "")
withCurrent := func() ([]*contexts.Context, string, error) {
return []*contexts.Context{{Name: "prod"}}, "prod", nil
}
t.Run("current context with a stored token is logged in", func(t *testing.T) {
importListContexts = withCurrent
importTokenForContext = func(*contexts.Context) (string, error) { return "stored-token", nil }
if !importLoggedIn() {
t.Fatal("context with a token should count as logged in")
}
})
t.Run("current context with a missing token is NOT logged in", func(t *testing.T) {
importListContexts = withCurrent
importTokenForContext = func(*contexts.Context) (string, error) {
return "", errors.New("no token stored")
}
if importLoggedIn() {
t.Fatal("context present but token missing must not count as logged in")
}
})
t.Run("no current context is not logged in", func(t *testing.T) {
importListContexts = func() ([]*contexts.Context, string, error) { return nil, "", nil }
importTokenForContext = func(*contexts.Context) (string, error) { return "stored-token", nil }
if importLoggedIn() {
t.Fatal("no current context should not count as logged in")
}
})
t.Run("env token counts as logged in even with no context", func(t *testing.T) {
t.Setenv(auth.EnvTokenVar, "env-token")
importListContexts = func() ([]*contexts.Context, string, error) { return nil, "", nil }
if !importLoggedIn() {
t.Fatal("ENTIRE_TOKEN should count as logged in")
}
})
}