git-remote-entire: case-insensitive core URL comparison via shared helper · Entire

git-remote-entire: case-insensitive core URL comparison via shared helper

96c8d87·

Soph·1mo ago·4 files·+37 added/-9 removed

Core URL scheme and DNS host are case-insensitive (RFC 3986); the prior comparisons folded only the trailing slash, so a mixed-case aud or issuer would fail to match an otherwise-identical core. Extract auth.EqualCoreURL (trailing-slash- and case-insensitive) and use it for both the ENTIRE_TOKEN trust gate (coreTrusted) and context matching (formerly sameIssuer) so the two agree on core-URL identity. Safe for the trust gate: case folding only makes variants of the same DNS host match, never a different host.

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

Sessions

baf4d553f9bdView transcript

Changes

4

104 unmodified lines

105
106
107
108
108
109
110
111
13 unmodified lines

125
126
127
128
129
130
128
129
130
131
132
133
134
135
136
137
138
31 unmodified lines

170
171
172
168
173
174
175
176

104 unmodified lines

// uniqueness.
func pickContextName(f *contexts.File, coreURL, handle string) string {
    for _, c := range f.Contexts {
        if sameIssuer(c.CoreURL, coreURL) && c.Handle == handle {
            if EqualCoreURL(c.CoreURL, coreURL) && c.Handle == handle {
                return c.Name
            }
        }
    }
}

// sameIssuer compares two core URLs ignoring a trailing slash.
func sameIssuer(a, b string) bool {
    return strings.TrimRight(a, "/") == strings.TrimRight(b, "/")
}
// EqualCoreURL reports whether two core URLs denote the same origin, ignoring
// a trailing slash and host case. URL scheme and DNS host are case-insensitive
// (RFC 3986 §3.1, §3.2.2); core URLs are validated bare origins (no path), so a
// whole-string case fold is equivalent to folding only scheme+host here. Shared
// by context matching and the ENTIRE_TOKEN trust gate so both agree on what
// counts as "the same core".
func EqualCoreURL(a, b string) bool {
    return strings.EqualFold(strings.TrimRight(a, "/"), strings.TrimRight(b, "/"))
}

// MigrateLegacyLoginContext bridges users who logged in before the

// issuer alone would skip a legacy bob@core just because alice@core (e.g.
// from another CLI) already exists, leaving Bob without a context.
for _, c := range f.Contexts {
    if sameIssuer(c.CoreURL, claims.Issuer) && c.Handle == handle {
        if EqualCoreURL(c.CoreURL, claims.Issuer) && c.Handle == handle {
            return false, nil
        }
    }
}

Mcmd/entire/cli/auth/contexts.go+10/-5

23 unmodified lines

24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50

23 unmodified lines

return header + "." + payload + "." + enc.EncodeToString([]byte("sig")) }

func TestEqualCoreURL(t *testing.T) { t.Parallel() tests := []struct { a, b string want bool }{ {"https://core.us.entire.io", "https://core.us.entire.io", true}, {"https://core.us.entire.io/", "https://core.us.entire.io", true}, {"https://Core.US.Entire.IO", "https://core.us.entire.io", true}, {"HTTPS://core.us.entire.io", "https://core.us.entire.io", true}, {"https://core.us.entire.io", "https://core.eu.entire.io", false}, {"", "https://core.us.entire.io", false}, {"", "", true}, } for _, tc := range tests { if got := EqualCoreURL(tc.a, tc.b); got != tc.want { t.Errorf("EqualCoreURL(%q, %q) = %v, want %v", tc.a, tc.b, got, tc.want) } } }

func TestRecordLoginContext_WritesContextAndToken(t *testing.T) { // Sets ENTIRE_CONFIG_DIR and swaps the keyring backend — process-global // state, so this test cannot run in parallel. }

Mcmd/entire/cli/auth/contexts_test.go+21

200 unmodified lines

201
202
203
204
205
204
205
206
207
207
208
209
209
210
211
212

200 unmodified lines

// coreTrusted reports whether coreURL is in the cluster's advertised core
// set, comparing on trailing-slash-insensitive equality to match how core
// URLs are compared elsewhere (contexts.ContextsForIssuer, auth.sameIssuer).
// set, comparing via auth.EqualCoreURL (trailing-slash- and host-case-
// insensitive) so the trust gate agrees with how core URLs are matched
// during context resolution.
func coreTrusted(coreURL string, trusted []string) bool {
    want := strings.TrimRight(coreURL, "/")
    for _, t := range trusted {
        if strings.TrimRight(t, "/") == want {
            if auth.EqualCoreURL(coreURL, t) {
                return true
            }
        }
    }
}

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

50 unmodified lines

51 52 53 54 55 56 57 58

50 unmodified lines

{"exact match", "https://core.us.entire.io", true}, {"trailing slash on candidate", "https://core.us.entire.io/", true}, {"trailing slash on trusted entry", "https://core.eu.entire.io", true}, {"mixed-case host matches", "https://Core.US.Entire.IO", true}, {"mixed-case scheme matches", "HTTPS://core.us.entire.io", true}, {"not in set", "https://attacker.example.com", false}, {"empty against set", "", false}, } }`