# 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

- cmd

- entire/cli/auth

- Mcontexts.go+10/-5

- Mcontexts_test.go+21

- git-remote-entire

- Mmain.go+4/-4

- Mmain_test.go+2

```
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},
	}
}`
