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
- Redact userinfo in CoreURLFromEnvToken error messages (u.Redacted())
- Fail closed with a clear "ENTIRE_TOKEN is set but blank" message on a whitespace-only token instead of the raw JWT-parse error; truly empty is still treated as unset by the caller and falls back to context auth.
- Rename "core" -> "login server" in resolveCreds doc comments.
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
Sessions
b5f6f2ff8832 View transcript
Changes
3
cmd
entire/cli/auth
Menv_token.go +14/-6
Menv_token_test.go +13
git-remote-entire
Mmain.go +3/-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