fix(repo): resolve `mirror get` clone URLs via that cluster's core · Entire

fix(repo): resolve mirror get clone URLs via that cluster's core

5a02cce→main· toothbrush·1w ago·3 files·+166 added/-8 removed

entire repo mirror get entire://<cluster>/gh/<owner>/<repo> listed mirrors on the active context's core, so a clone URL for a cluster in a different federation failed with "no mirror matching" until the user manually switched contexts with entire auth use. The clone URL already names its cluster; dial the core fronting it — discovered from the cluster's /.well-known/entire-cluster.json and authenticated with the matching local context — the same routing mirror create/remove (PR #1475) and repo clone --cluster (PR #1529) already use. A ULID ref carries no cluster coordinate and stays on the active context.

Adds runCoreObjectForCluster (mirroring runCoreListForCluster) and a clusterCoreClient test seam alongside activeCoreClient so the routing decision is pinned by command-level tests without live discovery.

Co-Authored-By: Claude Fable 5 noreply@anthropic.com

Changes

3

214 unmodified lines

// field/value list (default) or raw JSON (--json), reusing the same column definition as the matching list view. func runCoreObject[T any](cmd *cobra.Command, headers []string, row func(T) []string, fn func(ctx context.Context, c *coreapi.Client) (*T, error)) error { return runCore(cmd, func(ctx context.Context, c *coreapi.Client) error { return runCore(cmd, renderCoreObject(cmd, headers, row, fn)) }) }

// runCoreObjectForCluster is runCoreObject for a resource-provider command (see runCoreForCluster): identical field/JSON rendering, but dialing the core that fronts clusterHost rather than the active context. func runCoreObjectForCluster[T any](cmd *cobra.Command, clusterHost string, headers []string, row func(T) []string, fn func(ctx context.Context, c *coreapi.Client) (*T, error)) error { return runCoreForCluster(cmd, clusterHost, renderCoreObject(cmd, headers, row, fn)) }

// renderCoreObject builds the run-function shared by runCoreObject and runCoreObjectForCluster: fetch via fn, then render as a field/value list (default) or raw JSON (--json). Kept separate from the client-selection so the two object variants differ only in which core they dial (mirroring renderCoreList). func renderCoreObject[T any](cmd *cobra.Command, headers []string, row func(T) []string, fn func(ctx context.Context, c *coreapi.Client) (*T, error)) func(context.Context, *coreapi.Client) error { return func(ctx context.Context, c *coreapi.Client) error { item, err := fn(ctx, c) if err != nil { return err } return printFields(cmd.OutOrStdout(), headers, row(*item)) } } // tableStyles holds the foreground styles for the human table/field views, // without standing up the auth/context/TLS stack. var activeCoreClient = func(context.Context) (*coreapi.Client, error) { return coreapi.New() }

// clusterCoreClient builds the control-plane client for cluster-addressed commands (see runCoreForCluster). Same test seam as activeCoreClient — production wiring is coreapi.NewForCluster, which does live /.well-known discovery that command-level tests must not reach. var clusterCoreClient func(ctx context.Context, clusterHost string) (*coreapi.Client, error) = coreapi.NewForCluster

// runCore is the shared base for every active-context control-plane command: it owns the preamble only — silence usage, build the client, map API errors — and leaves all rendering to fn. The delete/revoke verbs call it // cluster_host". See coreapi.NewForCluster. func runCoreForCluster(cmd *cobra.Command, clusterHost string, fn func(ctx context.Context, c *coreapi.Client) error) error { return runCoreClient(cmd, func(ctx context.Context) (*coreapi.Client, error) { return coreapi.NewForCluster(ctx, clusterHost) }, fn) }

Mcmd/entire/cli/corecmd.go+25/-3

422 unmodified lines

Short: "Show a mirror by ULID or clone URL",
Long: "Show a mirror. <mirror> is either a mirror ULID or an entire:// clone " +
"URL\n(entire://<cluster>/gh/<owner>/<repo>) — the form `mirror list` " +
"prints and `git clone` accepts.",
Example: "  entire repo mirror get 01KS6KFJR2XS6PZ188MVYE07AN\n" +
"  entire repo mirror get entire://aws-us-east-2.entire.io/gh/octocat/hello-world",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
    return runCoreObject(cmd, mirrorColumns, mirrorRow, func(ctx context.Context, c *coreapi.Client) (*coreapi.Mirror, error) {
        mirrorID, err := resolveMirrorRef(ctx, c, args[0])
        ref := args[0]
        show := func(ctx context.Context, c *coreapi.Client) (*coreapi.Mirror, error) {
            mirrorID, err := resolveMirrorRef(ctx, c, ref)
            if err != nil {
                return nil, err
            }
            return c.GetMirror(ctx, coreapi.GetMirrorParams{MirrorId: mirrorID})
        }
    }
    // A ULID carries no cluster coordinate, so it can only be looked up
    // on the active context's core. A clone URL names its cluster — dial
    // the core fronting that cluster (discovered from its well-known and
    // authenticated with the matching local context, the same path
    // create/remove use), so the lookup works when the mirror lives in a
    // federation other than the active login instead of failing with
    // "no mirror matching".
    if looksLikeULID(ref) {
        return runCoreObject(cmd, mirrorColumns, mirrorRow, show)
    }
    clusterHost, _, _, _, err := parseMirrorCloneURL(ref)
    if err != nil {
        cmd.SilenceUsage = true
        return badMirrorRefErr(err)
    }
    return runCoreObjectForCluster(cmd, clusterHost, mirrorColumns, mirrorRow, show)
},
}
}

Mcmd/entire/cli/repo_mirror.go+32/-5


// TestRepoMirrorGet_Routing pins which core mirror get <ref> dials. A clone // URL names its cluster, so it must be resolved on the core fronting that // cluster (clusterCoreClient), not the active context — the original bug: // mirror get entire://<cluster>/… for a cluster in a federation other than // the active login failed with "no mirror matching" until the user switched // contexts. A ULID carries no cluster coordinate and stays on the active // context; an unparseable ref must error before dialing anything. func TestRepoMirrorGet_Routing(t *testing.T) { const mirrorULID = "0123456789ABCDEFGHJKMNPQRS" const clusterHost = "eukanuba.partial.to" const cloneURL = "entire://" + clusterHost + "/gh/entirehq/librarian"

// mirrorServer answers both the list (clone-URL resolution) and the // GetMirror-by-ULID calls for the librarian mirror. mirrorServer := func(t *testing.T) *httptest.Server { t.Helper() srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") switch r.URL.Path { case mirrorsAPIPath: assert.NoError(t, printJSON(w, &coreapi.ListMirrorsOutputBody{Mirrors: []coreapi.Mirror{ {MirrorId: mirrorULID, Owner: "entirehq", Repo: "librarian", ClusterHost: clusterHost}, }})) case mirrorsAPIPath + "/" + mirrorULID: assert.NoError(t, printJSON(w, &coreapi.Mirror{ MirrorId: mirrorULID, Owner: "entirehq", Repo: "librarian", ClusterHost: clusterHost, IsPrivate: coreapi.NewOptBool(true), })) default: t.Errorf("unexpected request path %q", r.URL.Path) w.WriteHeader(http.StatusNotFound) } })) t.Cleanup(srv.Close) return srv } seamActive := func(t *testing.T, fn func(context.Context) (*coreapi.Client, error)) { t.Helper() prev := activeCoreClient activeCoreClient = fn t.Cleanup(func() { activeCoreClient = prev }) } seamCluster := func(t *testing.T, fn func(context.Context, string) (*coreapi.Client, error)) { t.Helper() prev := clusterCoreClient clusterCoreClient = fn t.Cleanup(func() { clusterCoreClient = prev }) } runGet := func(t *testing.T, ref string) (string, error) { t.Helper() cmd := newRepoCmd() var out, errW bytes.Buffer cmd.SetOut(&out) cmd.SetErr(&errW) cmd.SetArgs([]string{"mirror", "get", ref}) err := cmd.ExecuteContext(t.Context()) return out.String(), err }

t.Run("clone URL dials the cluster's core, not the active context", func(t *testing.T) { srv := mirrorServer(t) seamActive(t, func(context.Context) (*coreapi.Client, error) { t.Error("clone-URL get dialed the active context's core") return nil, errors.New("wrong core") }) var gotHost string seamCluster(t, func(_ context.Context, host string) (*coreapi.Client, error) { gotHost = host return coreapi.NewWithBearer(srv.URL, "tok") }) out, err := runGet(t, cloneURL) require.NoError(t, err) require.Equal(t, clusterHost, gotHost, "must resolve on the clone URL's cluster") require.Contains(t, out, "entirehq/librarian") require.Contains(t, out, cloneURL) })

t.Run("ULID dials the active context", func(t *testing.T) { srv := mirrorServer(t) seamActive(t, func(context.Context) (*coreapi.Client, error) { return coreapi.NewWithBearer(srv.URL, "tok") }) seamCluster(t, func(_ context.Context, host string) (*coreapi.Client, error) { t.Errorf("ULID get dialed cluster core %q; a ULID has no cluster coordinate", host) return nil, errors.New("wrong core") }) out, err := runGet(t, mirrorULID) require.NoError(t, err) require.Contains(t, out, "entirehq/librarian") })

t.Run("unparseable ref errors before dialing any core", func(t *testing.T) { seamActive(t, func(context.Context) (*coreapi.Client, error) { t.Error("unparseable ref dialed the active context's core") return nil, errors.New("no dial expected") }) seamCluster(t, func(context.Context, string) (*coreapi.Client, error) { t.Error("unparseable ref dialed a cluster core") return nil, errors.New("no dial expected") }) _, err := runGet(t, "not-a-url") require.Error(t, err) require.ErrorContains(t, err, "pass a mirror ULID or a clone URL") }) }

func TestMirrorRow(t *testing.T) { t.Parallel() tests := []struct { ...