feat(git-remote-entire): surface wrong-cluster clone errors clearly · Entire
feat(git-remote-entire): surface wrong-cluster clone errors clearly
97aa0c9→main·
toothbrush·2w ago·3 files·+96 added/-6 removed
When a repo lives on a different cluster than the one in the entire:// URL, the data plane rejects the token exchange with an RFC 8693 invalid_target carrying an error_description naming the correct host. Previously this surfaced as a raw, multiply-wrapped HTTP 400 JSON blob.
Now git-remote-entire detects this case and prints an actionable message
naming the correct host and the corrected git clone entire://... URL.
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
Sessions
7cf3c440ed71View transcript
Changes
3
cmd/git-remote-entire
Mmain.go+32/-1
Mmain_test.go+57
internal/entireclient/httputil
Moauth.go+7/-5
import (
"context"
"errors"
"fmt"
"io"
"net/http"
"net/url"
"os"
"os/signal"
"regexp"
"runtime"
"strings"
"syscall"
"github.com/entireio/cli/cmd/entire/cli/versioninfo"
"github.com/entireio/cli/internal/entireclient/clusterdiscovery"
"github.com/entireio/cli/internal/entireclient/httpclient"
"github.com/entireio/cli/internal/entireclient/httputil"
"github.com/entireio/cli/internal/entireclient/repocreds"
"github.com/entireio/cli/internal/entireclient/userdirs"
"github.com/entireio/cli/internal/remotehelper"
)
// wrongClusterRe extracts the host that actually serves the repo from the
// data plane's invalid_target error_description (RFC 8693). The data plane
// emits this when the audience host doesn't host the repo but a sibling
// cluster does, naming the correct host so we can point the user at it. The
// phrasing is "… it lives on "lives on "([^"]+)")
// fatalMessage renders the stderr "fatal: …" line for a transfer error. When // the failure is the data plane reporting that the repo lives on a different // cluster, it special-cases the raw OAuth chain into an actionable message // naming the correct host (and the corrected entire:// URL). Everything else // falls back to the verbatim error. func fatalMessage(err error, parsedURL *url.URL) string { var oe *httputil.OAuthError if errors.As(err, &oe) && oe.Code == "invalid_target" { if m := wrongClusterRe.FindStringSubmatch(oe.Description); m != nil { host := m[1] corrected := (&url.URL{Scheme: "entire", Host: host, Path: parsedURL.Path}).String() return fmt.Sprintf("fatal: this repository is not hosted on %s; it lives on %s.\nRe-run against the correct host, e.g.:\n\n git clone %s\n", parsedURL.Host, host, corrected) } } return fmt.Sprintf("fatal: %v\n", err) }
// loadedVersion populates the build info and returns the resolved version. func loadedVersion() string { versioninfo.Load() }
func TestFatalMessage(t *testing.T) {
t.Parallel()
parsedURL := &url.URL{Scheme: "entire", Host: "aws-us-east-2.entire.io", Path: "/et/paul/dogbark"}
wrongCluster := &httputil.OAuthError{
Status: http.StatusBadRequest,
Code: "invalid_target",
Description: audience host "aws-us-east-2.entire.io" does not host this repo; it lives on "aws-eu-central-1.entire.io" — re-target the request there,
Body: "{...}",
}
tests := []struct {
name string
err error
contains []string
notContains []string
}{
{
name: "wrong cluster names correct host and URL",
// Wrapped to mirror production: the OAuthError surfaces buried under
// several fmt.Errorf layers, so errors.As must dig it out.
err: fmt.Errorf("stateless-connect v2 info/refs: fetching info/refs from entry domain: repo-scoped token exchange: oauth token exchange: %w", wrongCluster),
contains: []string{
"aws-eu-central-1.entire.io",
"git clone entire://aws-eu-central-1.entire.io/et/paul/dogbark",
},
notContains: []string{"HTTP 400", "invalid_target"},
},
{
name: "invalid_target without lives-on hint falls back",
err: &httputil.OAuthError{Status: http.StatusBadRequest, Code: "invalid_target", Description: "no servable mirror", Body: "HTTP 400: no servable mirror"},
contains: []string{"fatal:", "no servable mirror"},
},
{
name: "unrelated error falls back verbatim",
err: errors.New("connection refused"),
contains: []string{"fatal: connection refused"},
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
got := fatalMessage(tc.err, parsedURL)
for _, sub := range tc.contains {
if !strings.Contains(got, sub) {
t.Errorf("fatalMessage() = %q, missing %q", got, sub)
}
}
for _, sub := range tc.notContains {
if strings.Contains(got, sub) {
t.Errorf("fatalMessage() = %q, should not contain %q", got, sub)
}
}
}
}
}