git-remote-entire: address PR review on ENTIRE_TOKEN path · Entire

git-remote-entire: address PR review on ENTIRE_TOKEN path

2d393e2→main

Soph·1mo ago·3 files·+30 added/-9 removed

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

Sessions

b5f6f2ff8832 View transcript

Changes

3

40 unmodified lines

41
42
43
44
45
46
47
48
49
50
51
52
53
54
16 unmodified lines

71
72
73
66
74
75
68
76
77
70
78
79
72
80
81
74
82
83
76
84
85
86
87

40 unmodified lines

// validated strictly. A token with no URL-shaped aud is rejected with a clear
// error rather than silently falling back to context resolution.
func CoreURLFromEnvToken(rawToken string) (string, error) {
    // A blank-but-present value (e.g. ENTIRE_TOKEN=" ") fails closed rather
    // than silently falling back to context auth — but give it a clearer
    // message than the raw JWT-parse error. Note: only whitespace-only values
    // reach here; a truly empty ENTIRE_TOKEN is treated as unset by the caller
    // and never enters the env-token path.
    if strings.TrimSpace(rawToken) == "" {
        return "", fmt.Errorf("%s is set but blank", EnvTokenVar)
    }
    claims, err := tokens.ParseClaims(rawToken)
    if err != nil {
        return "", fmt.Errorf("parse %s claims: %w", EnvTokenVar, err)
    }
}

16 unmodified lines

func validateCoreAudience(u *url.URL) (string, error) {
    switch {
    case u.Scheme != "https":
        return "", fmt.Errorf("%s aud %q must use https; refusing to exchange the token over %s", EnvTokenVar, u.String(), u.Scheme)
    case u.Host == "":
        return "", fmt.Errorf("%s aud %q has no host", EnvTokenVar, u.String())
    case u.User != nil:
        return "", fmt.Errorf("%s aud %q must not contain userinfo", EnvTokenVar, u.String())
    case u.Path != "" && u.Path != "/":
        return "", fmt.Errorf("%s aud %q must be a bare origin with no path", EnvTokenVar, u.String())
    case u.RawQuery != "":
        return "", fmt.Errorf("%s aud %q must not contain query parameters", EnvTokenVar, u.String())
    case u.Fragment != "":
        return "", fmt.Errorf("%s aud %q must not contain a fragment", EnvTokenVar, u.String())
    }
    return strings.TrimRight(u.Scheme + "://" + u.Host, "/"), nil
}

Mcmd/entire/cli/auth/env_token.go +14/-6

109 unmodified lines

110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128

109 unmodified lines

assert.Contains(t, err.Error(), EnvTokenVar)
}

func TestCoreURLFromEnvToken_BlankToken(t *testing.T) {
    t.Parallel()
    // A whitespace-only value reaches here (truly empty is treated as unset by
    // the caller) and must fail closed with a clear message, not the raw
    // JWT-parse error.
    for _, tok := range []string{" ", "\t", "\n", " \t\n "} {
        _, err := CoreURLFromEnvToken(tok)
        require.Error(t, err)
        assert.Contains(t, err.Error(), EnvTokenVar)
        assert.Contains(t, err.Error(), "blank")
    }
}

func TestCoreURLFromEnvToken_RejectsAlgNone(t *testing.T) {
    t.Parallel()
    // alg:none with a URL-shaped aud must still be rejected at the parse layer.
}

Mcmd/entire/cli/auth/env_token_test.go +13

164 unmodified lines

165
166
167
168
168
169
170
171
10 unmodified lines

182
183
184
185
185
186
187
188
4 unmodified lines

193
194
195
196
196
197
198
199

164 unmodified lines

// resolveCreds builds the repo-scoped token cache, choosing the auth source:
//   - ENTIRE_TOKEN set: use the env JWT verbatim as the login token, deriving
//     the core URL from its aud claim. Skips contexts.json and the keyring
//     entirely — the CI / workload-identity path. A non-URL aud is a hard
//     error, never a silent fallback to context resolution.

return repocreds.New(clusterCtx.CoreURL, clusterBaseURL, func(context.Context) (string, error) {
    return auth.LoginTokenForContext(clusterCtx)
}, httpClient), nil
}

Mcmd/git-remote-entire/main.go +3/-3