auth: drop test-only seam setter, dedup repo_token test setup · Entire

auth: drop test-only seam setter, dedup repo_token test setup

e771cac→main·

toothbrush·1mo ago·3 files·+23 added/-18 removed

Review cleanup: in-package tests swap the resolveContextForCluster var directly (matching data_api_test's stub idiom), so the production setter goes away; the duplicated store-sandboxing lines move into one helper.

Co-Authored-By: Claude Fable 5 noreply@anthropic.com

Sessions

7ae2626a5f50View transcript

[?
Auth Refactor: Eliminate Static FallbacksClaude Code·Fable 5.[1m]·1 step](/content/gh/entireio/cli/session/e6146684-ebfa-4f57-beff-34194cac8c2a#timeline-7ae2626a5f50/index.html)

Changes

3

32 unmodified lines

33
34
35
36
37
38
39
40
41
42
43
36
37
38

32 unmodified lines

// don't reach the network. Mirrors clusterdiscovery.ResolveContextForCluster.
var resolveContextForCluster resolveContextFunc = clusterdiscovery.ResolveContextForCluster

// setResolveContextForClusterForTest overrides the cluster-discovery seam
// and returns a cleanup func. Test-only.
func setResolveContextForClusterForTest(fn resolveContextFunc) func() {
    prev := resolveContextForCluster
    resolveContextForCluster = fn
    return func() { resolveContextForCluster = prev }
}

// repoExchangeTransportForTest, when non-nil, is the HTTP transport used by
// RepoScopedToken's exchange (and login refresh), so the wire form can be
// asserted without a live core. Production leaves it nil.

Mcmd/entire/cli/auth/repo_token.go-8

17 unmodified lines

18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
27
28
29
43
44
45
46
2 unmodified lines

49
50
51
38
52
53
54
41
55
56
57
58
128 unmodified lines

187
188
189
176
177
178
190
191
192
193
181
194
195
196
197

17 unmodified lines

"github.com/entireio/cli/internal/entireclient/tokenstore"
// sandboxRepoTokenStores redirects the token store and contexts.json (the
// legacy-login migration's write target) to temp locations.
func sandboxRepoTokenStores(t *testing.T) {
    t.Helper()
    t.Setenv("ENTIRE_CONFIG_DIR", t.TempDir())
    t.Cleanup(tokenstore.UseFileBackendForTesting(filepath.Join(t.TempDir(), "tokens.json")))
}

// stubResolveContextForCluster swaps the discovery seam for fn.
func stubResolveContextForCluster(t *testing.T, fn resolveContextFunc) {
    t.Helper()
    prev := resolveContextForCluster
    resolveContextForCluster = fn
    t.Cleanup(func() { resolveContextForCluster = prev })
}

// seedRepoTokenContext wires the two seams RepoScopedToken sits on: a
// file-backed token store holding a still-valid login JWT for a context on
// coreURL, and a discovery stub resolving any cluster to that context. The
// exchange transport is left to each test. Returns the seeded login JWT.
func seedRepoTokenContext(t *testing.T, coreURL string) string {
    t.Helper()
    // Sandbox the legacy-login migration's contexts.json writes.
    t.Setenv("ENTIRE_CONFIG_DIR", t.TempDir())
    t.Cleanup(tokenstore.UseFileBackendForTesting(filepath.Join(t.TempDir(), "tokens.json")))
    sandboxRepoTokenStores(t)

svc := tokenstore.CoreKeyringService(coreURL)
    jwt := makeJWT(t, fmt.Sprintf(`{"iss":%q,"handle":"alice","exp":%d}`, coreURL, time.Now().Add(2*time.Hour).Unix()))

c := &contexts.Context{Name: "alice@core", CoreURL: coreURL, Handle: "alice", KeychainService: svc}
    t.Cleanup(setResolveContextForClusterForTest(
    stubResolveContextForCluster(t,
    func(context.Context, string, string, string, *http.Client, clusterdiscovery.DebugFunc) (*contexts.Context, error) {
        return c, nil
    }))
    )
    return jwt
}

128 unmodified lines

// failure (no eligible login, ambiguous contexts, unreachable cluster) is
// returned verbatim — never papered over with a wrong-core exchange.
func TestRepoScopedToken_DiscoveryErrorSurfaces(t *testing.T) {
    t.Setenv("ENTIRE_CONFIG_DIR", t.TempDir())
    t.Cleanup(tokenstore.UseFileBackendForTesting(filepath.Join(t.TempDir(), "tokens.json")))
    t.Cleanup(setResolveContextForClusterForTest(
    sandboxRepoTokenStores(t)
    stubResolveContextForCluster(t,
    func(context.Context, string, string, string, *http.Client, clusterdiscovery.DebugFunc) (*contexts.Context, error) {
        return nil, errors.New("not logged in to a login server trusted by cluster x; run `entire login`")
    }))
    )
    t.Cleanup(SetRepoExchangeTransportForTest(failRoundTripper(t)))

_, err := RepoScopedToken(context.Background(), "x.entire.io", "/gh/o/r", "pull")

Mcmd/entire/cli/auth/repo_token_test.go+22/-9

1076 unmodified lines

1077
1078
1079
1080
1080
1081
1082
1083

1076 unmodified lines

var claudeErr *claudecode.ClaudeError
    switch {
    case errors.As(err, &claudeErr):
        switch claudeErr.Kind { //nolint:exhaustive // ClaudeErrorUnknown handled by default
        switch claudeErr.Kind {
        case claudecode.ClaudeErrorAuth:
            label := "Claude authentication failed"
            rows := []explainRow{