feat(grant): positional provider:handle grantees + repo clone URL (COR-699) · Entire

feat(grant): positional provider:handle grantees + repo clone URL (COR-699)

7ec1e0f· toothbrush·2w ago·7 files·+309 added/-228 removed

Address grantees as github:alice instead of --provider/--provider-user-id flag soup: grant {org,project,repo} add/remove now take a positional <target> <grantee>, resolving the handle to its provider user id via the control plane (new resolveGranteeProvider). remove also accepts an account ULID for the typed-id revoke route. Show the entire:// clone URL in repo get.

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

Sessions

3018b0b38bf3View transcript

Changes

7

1 unmodified line

2
3
4
5
5
6
7
34 unmodified lines

42
43
44
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
45
46
47
48
65
66
67
49
50
51
52
53
54
55
42 unmodified lines

98
99
100
116
101
102
118
119
120
103
104
105
106
107
108
122
123
124
125
126
127
128
129
130
131
132
133
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
143
133
134
135
26 unmodified lines

162
163
164
176
165
178
179
180
166
167
168
169
170
171
172
173
174
175
176
187
177
178
179
180
181
182
183
184
3 unmodified lines

188
189
190
197
191
192
193
11 unmodified lines

205
206
207
215
208
209
217
218
219
210
211
212
213
214
215
216
217
218
219
225
226
227
228
220
221
222
223
224
225
226
227
228
229
230
231
232
233
239
240
241
234
235
236
237
246
247
248
238
239
240
241
26 unmodified lines

268
269
270
281
271
283
272
273
274
286
287
288
289
275
276
277
278
279
291
292
293
294
295
280
281
282
283
284
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
285
286
287
288
320
321
322
323
289
290
291
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
10 unmodified lines

331
332
333
376
334
335
378
379
380
336
337
338
339
340
341
342
343
344
345
386
387
388
389
346
347
348
349
350
351
352
353
354
355
356
357
358
359
400
401
402
360
361
362
363
407
408
409
364
365
366
367
30 unmodified lines

398
399
400
446
401
402
448
403
404
450
451
452
453
405
406
407
408
409
410
455
456
457
458
459
411
412
413
414
415
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
416
417
418
419
484
485
486
487
420
421
422
423
492
493
494
495
496
497
498
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
505
454
455
456
457

1 unmodified line

import (
    "context"
    "errors"
    "fmt"

"github.com/spf13/cobra"
34 unmodified lines

}

// validateGrantGranteeType rejects grantee kinds the control plane no longer
// accepts when granting. A grant resolves to an account (from the provider
// identity), so "account" is the only valid kind ("" means the default,
// account). org/team granting was dropped server-side (COR-561) and the
// generated client enum is account-only, so catch it here with a clear message
// instead of an opaque enum-encoding error.
func validateGrantGranteeType(granteeType string) error {
    switch granteeType {
    case "", "account":
        return nil
    default:
        return fmt.Errorf("invalid --grantee-type %q: only \"account\" is supported", granteeType)
    }
}

// newGrantCmd is the hidden `entire grant` command group: manage access
// grants and org membership on the Entire control plane. Org, project, and
// repo each support add / list / remove. Surfaced via `entire labs`.
//
// Grantees are addressed by their identity provider + provider user id
// (e.g. --provider github --provider-user-id 12345), matching the control
// plane's grant model. Handle-based addressing is a follow-up.
// Grantees are addressed by a provider-qualified handle (e.g. github:alice),
// which the CLI resolves to the provider account behind the scenes. `remove`
// also accepts an account ULID to revoke a grant by id. Targets (org, project,
// repo) are addressed by name or ULID.
func newGrantCmd() *cobra.Command {
    cmd := &cobra.Command{
        Use:    "grant",
42 unmodified lines

}

func newGrantOrgAddCmd() *cobra.Command {
    var provider, providerUserID, role string
    cmd := &cobra.Command{
        Use:   "add <org>",
        Short: "Add a member to an org",
        Args:  cobra.ExactArgs(1),
        Use:     "add <org> <grantee>",
        Short:   "Add a member to an org",
        Long:    "Add a member (addressed as provider:handle, e.g. github:alice) to an org (name or ULID).",
        Example: "  entire grant org add acme github:alice --role admin",
        Args:    cobra.ExactArgs(2),
        RunE: func(cmd *cobra.Command, args []string) error {
            body := &coreapi.AddOrgMemberInputBody{
                Provider:       provider,
                ProviderUserId: providerUserID,
            }
            if role != "" {
                r, err := parseOrgRole(role)
                if err != nil {
                    cmd.SilenceUsage = true
                    return err
                }
                body.Role = coreapi.NewOptAddOrgMemberInputBodyRole(r)
            }
            return runCoreJSON(cmd, func(ctx context.Context, c *coreapi.Client) (any, error) {
                orgID, err := resolveOrgRef(ctx, c, args[0])
                if err != nil {
                    return nil, err
                }
                provider, providerUserID, err := resolveGranteeProvider(ctx, c, args[1])
                if err != nil {
                    return nil, err
                }
                body := &coreapi.AddOrgMemberInputBody{
                    Provider:       provider,
                    ProviderUserId: providerUserID,
                }
                if role != "" {
                    r, err := parseOrgRole(role)
                    if err != nil {
                        return nil, err
                    }
                    body.Role = coreapi.NewOptAddOrgMemberInputBodyRole(r)
                }
                return c.AddOrgMember(ctx, body, coreapi.AddOrgMemberParams{OrgId: orgID})
            })
        },
    }
    bindGranteeFlags(cmd, &provider, &providerUserID)
    cmd.Flags().StringVar(&role, "role", "", "org role: owner, admin, or member (default member)")
    return cmd
}

func newGrantOrgRemoveCmd() *cobra.Command {
    var provider, providerUserID string
    cmd := &cobra.Command{
        Use:   "remove <org>",
        Short: "Remove a member from an org",
        Args:  cobra.ExactArgs(1),
        Use:     "remove <org> <grantee>",
        Short:   "Remove a member from an org",
        Long:    "Remove a member (addressed as provider:handle, e.g. github:alice) from an org (name or ULID).",
        Example: "  entire grant org remove acme github:alice",
        Args:    cobra.ExactArgs(2),
        RunE: func(cmd *cobra.Command, args []string) error {
            return runCore(cmd, func(ctx context.Context, c *coreapi.Client) error {
                orgID, err := resolveOrgRef(ctx, c, args[0])
                if err != nil {
                    return err
                }
                return revokeGrant(cmd, "Removed", fmt.Sprintf("%s/%s from org %s", provider, providerUserID, args[0]), func() error {
                    provider, providerUserID, err := resolveGranteeProvider(ctx, c, args[1])
                    if err != nil {
                        return err
                    }
                    return c.RemoveOrgMember(ctx, coreapi.RemoveOrgMemberParams{
                        OrgId:          orgID,
                        Provider:       provider,
                        ProviderUserId: providerUserID,
                    })
                })
            })
    },
    }
    bindGranteeFlags(cmd, &provider, &providerUserID)
    return cmd
}

func newGrantProjectAddCmd() *cobra.Command {
    var provider, providerUserID, role, granteeType string
    cmd := &cobra.Command{
        Use:   "add <project>",
        Short: "Grant access to a project",
        Args:  cobra.ExactArgs(1),
        Use:     "add <project> <grantee>",
        Short:   "Grant a user access to a project",
        Long:    "Grant a user (addressed as provider:handle, e.g. github:alice) access to a project (name or ULID).",
        Example: "  entire grant project add widgets github:alice --role writer",
        Args:    cobra.ExactArgs(2),
        RunE: func(cmd *cobra.Command, args []string) error {
            if err := validateGrantRole(role); err != nil {
                cmd.SilenceUsage = true
                return err
            }
            if err := validateGrantGranteeType(granteeType); err != nil {
                cmd.SilenceUsage = true
                return err
            }
            return runCoreJSON(cmd, func(ctx context.Context, c *coreapi.Client) (any, error) {
                projID, err := resolveProjectRef(ctx, c, args[0])
                if err != nil {
                    return nil, err
                }
                provider, providerUserID, err := resolveGranteeProvider(ctx, c, args[1])
                if err != nil {
                    return nil, err
                }
                body := &coreapi.GrantProjectAccessInputBody{
                    Provider:       provider,
                    ProviderUserId: providerUserID,
                    Role:           coreapi.GrantProjectAccessInputBodyRole(role),
                }
                if granteeType != "" {
                    body.GranteeType = coreapi.NewOptGrantProjectAccessInputBodyGranteeType(coreapi.GrantProjectAccessInputBodyGranteeType(granteeType))
                }
                return c.GrantProjectAccess(ctx, body, coreapi.GrantProjectAccessParams{ProjectId: projID})
            })
        },
    }
    bindGranteeFlags(cmd, &provider, &providerUserID)
    cmd.Flags().StringVar(&role, "role", "", "project role (required)")
    cmd.Flags().StringVar(&granteeType, "grantee-type", "", "grantee kind: account (the only supported kind; default)")
    cmd.Flags().StringVar(&role, "role", "", "project role: reader, writer, or admin (required)")
    markRequired(cmd, "role")
    return cmd
}

func newGrantProjectRemoveCmd() *cobra.Command {
    var granteeType, granteeID, provider, providerUserID string
    cmd := &cobra.Command{
        Use:   "remove <project>",
        Use:   "remove <project> <grantee>",
        Short: "Revoke project access from a grantee",
        Long: "Revoke a grantee's access to a project (addressed by name or ULID). " +
            "Identify the grantee either by --provider/--provider-user-id (an " +
            "account, e.g. github + user id) or by --grantee-type account " +
            "--grantee-id <ULID>.",
        Args: cobra.ExactArgs(1),
        Example: "  entire grant project remove widgets github:alice",
        Args:    cobra.ExactArgs(2),
        RunE: func(cmd *cobra.Command, args []string) error {
            mode, err := parseGranteeMode(provider, providerUserID, granteeType, granteeID)
            if err != nil {
                cmd.SilenceUsage = true
                return err
            }
            return runCore(cmd, func(ctx context.Context, c *coreapi.Client) error {
                projID, err := resolveProjectRef(ctx, c, args[0])
                if err != nil {
                    return err
                }
                if mode == granteeModeProvider {
                    return revokeGrant(cmd, "Revoked", fmt.Sprintf("%s/%s from project %s", provider, providerUserID, args[0]), func() error {
                        return c.RevokeProjectAccessByProvider(ctx, coreapi.RevokeProjectAccessByProviderParams{
                            ProjectId:      projID,
                            Provider:       provider,
                            ProviderUserId: providerUserID,
                        })
                    })
                }
                return revokeGrant(cmd, "Revoked", fmt.Sprintf("%s %s from project %s", granteeType, granteeID, args[0]), func() error {
                    return c.RevokeProjectAccess(ctx, coreapi.RevokeProjectAccessParams{
                        ProjectId:   projID,
                        GranteeType: granteeType,
                        GranteeId:   granteeID,
                    })
                })
            return revokeProjectGrantee(ctx, cmd, c, projID, args[0], args[1])
        },
    }
    cmd.Flags().StringVar(&granteeType, "grantee-type", "", "grantee kind: account (with --grantee-id)")
    cmd.Flags().StringVar(&granteeID, "grantee-id", "", "grantee ULID (with --grantee-type)")
    cmd.Flags().StringVar(&provider, "provider", "", "identity provider, e.g. github (with --provider-user-id)")
    cmd.Flags().StringVar(&providerUserID, "provider-user-id", "", "provider-specific user id (with --provider)")
    return cmd
}

// granteeMode names the two ways `grant project remove` / `grant repo remove`
// can address a grantee.
type granteeMode int

const (
granteeModeProvider granteeMode = iota // --provider + --provider-user-id
granteeModeID                          // --grantee-type + --grantee-id
)

// parseGranteeMode validates that exactly one addressing mode was supplied
// and fully specified, returning which one. The two modes are mutually
// exclusive: a provider account (github + user id) hits the by-provider revoke
// route, while a ULID grantee hits the typed-id route that also covers org and
// team grantees.
func parseGranteeMode(provider, providerUserID, granteeType, granteeID string) (granteeMode, error) {
    byProvider := provider != "" || providerUserID != ""
    byID := granteeType != "" || granteeID != ""
    switch {
    case byProvider && byID:
        return 0, errors.New("specify either --provider/--provider-user-id or --grantee-type/--grantee-id, not both")
    case byProvider:
        if provider == "" || providerUserID == "" {
            return 0, errors.New("both --provider and --provider-user-id are required")
        }
        return granteeModeProvider, nil
    case byID:
        if granteeType == "" || granteeID == "" {
            return 0, errors.New("both --grantee-type and --grantee-id are required")
        }
        return granteeModeID, nil
    default:
        return 0, errors.New("identify the grantee with --provider/--provider-user-id or --grantee-type/--grantee-id")
    }
}

// revokeProjectGrantee revokes a grantee (provider:handle or account ULID) from
// a resolved project. A ULID grantee takes the typed-id route directly; a
// handle is resolved to its provider account first and takes the by-provider
// route. projectRef is the user's original (pre-resolution) project ref, used
// only for the success message.
func revokeProjectGrantee(ctx context.Context, cmd *cobra.Command, c *coreapi.Client, projID, projectRef, grantee string) error {
    if looksLikeULID(grantee) {
        return revokeGrant(cmd, "Revoked", fmt.Sprintf("account %s from project %s", grantee, projectRef), func() error {
            return c.RevokeProjectAccess(ctx, coreapi.RevokeProjectAccessParams{
                ProjectId:   projID,
                GranteeType: "account",
                GranteeId:   grantee,
            })
        })
    }
    provider, providerUserID, err := resolveGranteeProvider(ctx, c, grantee)
    if err != nil {
        return err
    }
    return revokeGrant(cmd, "Revoked", fmt.Sprintf("%s from project %s", grantee, projectRef), func() error {
        return c.RevokeProjectAccessByProvider(ctx, coreapi.RevokeProjectAccessByProviderParams{
            ProjectId:      projID,
            Provider:       provider,
            ProviderUserId: providerUserID,
        })
    })
}

// --- repo grants ----------------------------------------------------------

func newGrantRepoAddCmd() *cobra.Command {
    var provider, providerUserID, role, granteeType, project string
    cmd := &cobra.Command{
        Use:   "add <repo>",
        Short: "Grant access to a repo",
        Args:  cobra.ExactArgs(1),
        Use:     "add <repo> <grantee>",
        Short:   "Grant a user access to a repo",
        Long:    "Grant a user (addressed as provider:handle, e.g. github:alice) access to a repo (name or ULID).",
        Example: "  entire grant repo add web github:alice --project acme --role writer",
        Args:    cobra.ExactArgs(2),
        RunE: func(cmd *cobra.Command, args []string) error {
            if err := validateGrantRole(role); err != nil {
                cmd.SilenceUsage = true
                return err
            }
            if err := validateGrantGranteeType(granteeType); err != nil {
                cmd.SilenceUsage = true
                return err
            }
            return runCoreJSON(cmd, func(ctx context.Context, c *coreapi.Client) (any, error) {
                repoID, err := resolveRepoRef(ctx, c, args[0], project)
                if err != nil {
                    return nil, err
                }
                provider, providerUserID, err := resolveGranteeProvider(ctx, c, args[1])
                if err != nil {
                    return nil, err
                }
                body := &coreapi.GrantRepoAccessInputBody{
                    Provider:       provider,
                    ProviderUserId: providerUserID,
                    Role:           coreapi.GrantRepoAccessInputBodyRole(role),
                }
                if granteeType != "" {
                    body.GranteeType = coreapi.NewOptGrantRepoAccessInputBodyGranteeType(coreapi.GrantRepoAccessInputBodyGranteeType(granteeType))
                }
                return c.GrantRepoAccess(ctx, body, coreapi.GrantRepoAccessParams{RepoId: repoID})
            })
        },
    }
    bindGranteeFlags(cmd, &provider, &providerUserID)
    cmd.Flags().StringVar(&role, "role", "", "repo role (required)")
    cmd.Flags().StringVar(&granteeType, "grantee-type", "", "grantee kind: account (the only supported kind; default)")
    cmd.Flags().StringVar(&role, "role", "", "repo role: reader, writer, or admin (required)")
    bindRepoProjectFlag(cmd, &project)
    markRequired(cmd, "role")
    return cmd
}

func newGrantRepoRemoveCmd() *cobra.Command {
    var granteeType, granteeID, provider, providerUserID, project string
    cmd := &cobra.Command{
        Use:   "remove <repo>",
        Use:   "remove <repo> <grantee>",
        Short: "Revoke repo access from a grantee",
        Long: "Revoke a grantee's access to a repo. Identify the grantee either by " +
            "--provider/--provider-user-id (an account, e.g. github + user id) or by " +
            "--grantee-type account --grantee-id <ULID>.",
        Args: cobra.ExactArgs(1),
        Long: "Revoke a grantee's access to a repo (addressed by name or ULID). " +
            "The grantee is a provider-qualified handle (e.g. github:alice) or an " +
            "account ULID.",
        Example: "  entire grant repo remove web github:alice --project acme",
        Args:    cobra.ExactArgs(2),
        RunE: func(cmd *cobra.Command, args []string) error {
            mode, err := parseGranteeMode(provider, providerUserID, granteeType, granteeID)
            if err != nil {
                cmd.SilenceUsage = true
                return err
            }
            return runCore(cmd, func(ctx context.Context, c *coreapi.Client) error {
                repoID, err := resolveRepoRef(ctx, c, args[0], project)
                if err != nil {
                    return err
                }
                if mode == granteeModeProvider {
                    return revokeGrant(cmd, "Revoked", fmt.Sprintf("%s/%s from repo %s", provider, providerUserID, args[0]), func() error {
                        return c.RevokeRepoAccessByProvider(ctx, coreapi.RevokeRepoAccessByProviderParams{
                            RepoId:         repoID,
                            Provider:       provider,
                            ProviderUserId: providerUserID,
                        })
                    })
                }
                return revokeGrant(cmd, "Revoked", fmt.Sprintf("%s %s from repo %s", granteeType, granteeID, args[0]), func() error {
                    return c.RevokeRepoAccess(ctx, coreapi.RevokeRepoAccessParams{
                        RepoId:      repoID,
                        GranteeType: granteeType,
                        GranteeId:   granteeID,
                    })
                })
            return revokeRepoGrantee(ctx, cmd, c, repoID, args[0], args[1])
        },
    }
    cmd.Flags().StringVar(&granteeType, "grantee-type", "", "grantee kind: account (with --grantee-id)")
    cmd.Flags().StringVar(&granteeID, "grantee-id", "", "grantee ULID (with --grantee-type)")
    cmd.Flags().StringVar(&provider, "provider", "", "identity provider, e.g. github (with --provider-user-id)")
    cmd.Flags().StringVar(&providerUserID, "provider-user-id", "", "provider-specific user id (with --provider)")
    bindRepoProjectFlag(cmd, &project)
    return cmd
}

// bindGranteeFlags wires the shared --provider / --provider-user-id pair
// that identifies a grantee across the org/project/repo add+remove verbs,
// marking both required.
func bindGranteeFlags(cmd *cobra.Command, provider, providerUserID *string) {
    cmd.Flags().StringVar(provider, "provider", "", "identity provider (e.g. github) (required)")
    cmd.Flags().StringVar(providerUserID, "provider-user-id", "", "provider-specific user id (required)")
    markRequired(cmd, "provider", "provider-user-id")

// revokeRepoGrantee mirrors revokeProjectGrantee for repos: a ULID grantee
// takes the typed-id revoke route, a provider:handle is resolved first and takes
// the by-provider route. repoRef is the user's original repo ref, for messaging.
func revokeRepoGrantee(ctx context.Context, cmd *cobra.Command, c *coreapi.Client, repoID, repoRef, grantee string) error {
    if looksLikeULID(grantee) {
        return revokeGrant(cmd, "Revoked", fmt.Sprintf("account %s from repo %s", grantee, repoRef), func() error {
            return c.RevokeRepoAccess(ctx, coreapi.RevokeRepoAccessParams{
                RepoId:      repoID,
                GranteeType: "account",
                GranteeId:   grantee,
            })
        })
    }
    provider, providerUserID, err := resolveGranteeProvider(ctx, c, grantee)
    if err != nil {
        return err
    }
    return revokeGrant(cmd, "Revoked", fmt.Sprintf("%s from repo %s", grantee, repoRef), func() error {
        return c.RevokeRepoAccessByProvider(ctx, coreapi.RevokeRepoAccessByProviderParams{
            RepoId:         repoID,
            Provider:       provider,
            ProviderUserId: providerUserID,
        })
    })
}

// revokeGrant runs a grant-removal API call idempotently. A 404 means the
// grantee already has no such grant — the desired end state — so it's reported
// as a no-op rather than surfaced as a raw error, matching runControlPlaneDelete.
// verb is the success word ("Revoked"/"Removed"); subject describes the grant,
// e.g. "github/12345 from repo acme".
// e.g. "github:alice from repo acme".
func revokeGrant(cmd *cobra.Command, verb, subject string, revoke func() error) error {
    if err := revoke(); err != nil {
        if isCoreNotFound(err) {
//