From b935e812c7c420d1920bc60b2c2fbe54cde45d90 Mon Sep 17 00:00:00 2001 From: paul <423357+toothbrush@users.noreply.github.com> Date: Sun, 28 Jun 2026 18:22:03 +0930 Subject: [PATCH 1/5] feat(grant): positional provider:handle grantees + repo clone URL (COR-699) Address grantees as `github:alice` instead of --provider/--provider-user-id flag soup: `grant {org,project,repo} add/remove` now take a positional ` `, 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) Entire-Checkpoint: 3018b0b38bf3 --- cmd/entire/cli/grant.go | 293 ++++++++++++---------------- cmd/entire/cli/grant_test.go | 35 ---- cmd/entire/cli/grant_wiring_test.go | 67 +++++-- cmd/entire/cli/repo.go | 18 +- cmd/entire/cli/repo_test.go | 35 ++++ cmd/entire/cli/resolveref.go | 40 ++++ cmd/entire/cli/resolveref_test.go | 49 +++++ 7 files changed, 309 insertions(+), 228 deletions(-) diff --git a/cmd/entire/cli/grant.go b/cmd/entire/cli/grant.go index b5bc226dfc..09b8b25701 100644 --- a/cmd/entire/cli/grant.go +++ b/cmd/entire/cli/grant.go @@ -2,7 +2,6 @@ package cli import ( "context" - "errors" "fmt" "github.com/spf13/cobra" @@ -43,28 +42,14 @@ func validateGrantRole(role string) error { } } -// 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", @@ -113,34 +98,38 @@ func newGrantOrgCmd() *cobra.Command { } func newGrantOrgAddCmd() *cobra.Command { - var provider, providerUserID, role string + var role string cmd := &cobra.Command{ - Use: "add ", - Short: "Add a member to an org", - Args: cobra.ExactArgs(1), + Use: "add ", + 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 } @@ -173,18 +162,23 @@ func newGrantOrgListCmd() *cobra.Command { } func newGrantOrgRemoveCmd() *cobra.Command { - var provider, providerUserID string cmd := &cobra.Command{ - Use: "remove ", - Short: "Remove a member from an org", - Args: cobra.ExactArgs(1), + Use: "remove ", + 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 revokeGrant(cmd, "Removed", fmt.Sprintf("%s from org %s", args[1], args[0]), func() error { return c.RemoveOrgMember(ctx, coreapi.RemoveOrgMemberParams{ OrgId: orgID, Provider: provider, @@ -194,7 +188,6 @@ func newGrantOrgRemoveCmd() *cobra.Command { }) }, } - bindGranteeFlags(cmd, &provider, &providerUserID) return cmd } @@ -212,40 +205,37 @@ func newGrantProjectCmd() *cobra.Command { } func newGrantProjectAddCmd() *cobra.Command { - var provider, providerUserID, role, granteeType string + var role string cmd := &cobra.Command{ - Use: "add ", - Short: "Grant access to a project", - Args: cobra.ExactArgs(1), + Use: "add ", + 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 } @@ -278,85 +268,53 @@ func newGrantProjectListCmd() *cobra.Command { } func newGrantProjectRemoveCmd() *cobra.Command { - var granteeType, granteeID, provider, providerUserID string cmd := &cobra.Command{ - Use: "remove ", + Use: "remove ", 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 .", - Args: cobra.ExactArgs(1), + "The grantee is a provider-qualified handle (e.g. github:alice) or an " + + "account ULID.", + 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 ---------------------------------------------------------- @@ -373,40 +331,37 @@ func newGrantRepoCmd() *cobra.Command { } func newGrantRepoAddCmd() *cobra.Command { - var provider, providerUserID, role, granteeType, project string + var role, project string cmd := &cobra.Command{ - Use: "add ", - Short: "Grant access to a repo", - Args: cobra.ExactArgs(1), + Use: "add ", + 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 @@ -443,66 +398,60 @@ func newGrantRepoListCmd() *cobra.Command { } func newGrantRepoRemoveCmd() *cobra.Command { - var granteeType, granteeID, provider, providerUserID, project string + var project string cmd := &cobra.Command{ - Use: "remove ", + Use: "remove ", 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 .", - 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) { diff --git a/cmd/entire/cli/grant_test.go b/cmd/entire/cli/grant_test.go index dc872da66c..0bab40d231 100644 --- a/cmd/entire/cli/grant_test.go +++ b/cmd/entire/cli/grant_test.go @@ -20,41 +20,6 @@ func TestValidateGrantRole(t *testing.T) { } } -func TestParseGranteeMode(t *testing.T) { - t.Parallel() - tests := []struct { - name string - provider, providerUserID, gType, gID string - want granteeMode - wantErr bool - }{ - {name: "provider mode", provider: "github", providerUserID: "123", want: granteeModeProvider}, - {name: "id mode", gType: "org", gID: "01J0", want: granteeModeID}, - {name: "both modes rejected", provider: "github", providerUserID: "123", gType: "org", gID: "01J0", wantErr: true}, - {name: "partial provider", provider: "github", wantErr: true}, - {name: "partial id", gType: "org", wantErr: true}, - {name: "nothing", wantErr: true}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - t.Parallel() - got, err := parseGranteeMode(tt.provider, tt.providerUserID, tt.gType, tt.gID) - if tt.wantErr { - if err == nil { - t.Errorf("parseGranteeMode(%q,%q,%q,%q) expected error", tt.provider, tt.providerUserID, tt.gType, tt.gID) - } - return - } - if err != nil { - t.Fatalf("parseGranteeMode: %v", err) - } - if got != tt.want { - t.Errorf("got mode %d, want %d", got, tt.want) - } - }) - } -} - func TestParseOrgRole(t *testing.T) { t.Parallel() tests := []struct { diff --git a/cmd/entire/cli/grant_wiring_test.go b/cmd/entire/cli/grant_wiring_test.go index 17dfa5fe4a..5a4c8baa33 100644 --- a/cmd/entire/cli/grant_wiring_test.go +++ b/cmd/entire/cli/grant_wiring_test.go @@ -3,10 +3,13 @@ package cli import ( "net/http" "net/http/httptest" + "strings" "testing" "github.com/spf13/cobra" "github.com/stretchr/testify/require" + + "github.com/entireio/cli/internal/coreapi" ) // Valid ULID-shaped refs (26 Crockford base32 chars, no I/L/O/U) so the remove @@ -18,11 +21,34 @@ const ( wiringGranteeULID = "01HZX7QABCDEFGHJKMNPQRSTVZ" ) +// grantWiringHandler serves the handle-resolution GET (so a provider:handle +// grantee resolves to a numeric provider user id) and records the subsequent +// revoke DELETE. record is called with the DELETE's method and path; deleteFn +// writes the DELETE response (e.g. 204 or a 404 problem). +func grantWiringHandler(t *testing.T, record func(method, path string), deleteFn func(w http.ResponseWriter)) http.HandlerFunc { + t.Helper() + return func(w http.ResponseWriter, r *http.Request) { + if r.Method == http.MethodGet && strings.Contains(r.URL.Path, "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/identity/handles/") { + w.Header().Set("Content-Type", "application/json") + if err := writeJSON(w, &coreapi.ResolvedIdentity{ + AccountId: wiringGranteeULID, + Provider: providerGitHub, + Handle: "alice", + ProviderUserId: "12345", + }); err != nil { + t.Errorf("encode identity: %v", err) + } + return + } + record(r.Method, r.URL.Path) + deleteFn(w) + } +} + // TestGrantRemove_RouteWiring drives the grant remove commands through cobra and -// asserts the grantee-mode → route selection: --provider/--provider-user-id must -// hit the by-provider revoke route, while --grantee-type/--grantee-id must hit -// the typed-id route. This locks in the mode→route mapping that grant_test.go's -// pure-helper tests (parseGranteeMode) can't observe. +// asserts the grantee-form → route selection: a provider:handle grantee resolves +// then hits the by-provider revoke route, while an account ULID hits the +// typed-id route directly. This locks in the grantee→route mapping. // // Not parallel: runDeleteCmd swaps the package-level activeCoreClient seam. func TestGrantRemove_RouteWiring(t *testing.T) { @@ -35,31 +61,31 @@ func TestGrantRemove_RouteWiring(t *testing.T) { { "repo/by-provider", newGrantRepoRemoveCmd, - []string{wiringRepoULID, "--provider", "github", "--provider-user-id", "12345"}, + []string{wiringRepoULID, "github:alice"}, "/api/v1/repos/" + wiringRepoULID + "/grants/account/github/12345", }, { "repo/by-grantee-id", newGrantRepoRemoveCmd, - []string{wiringRepoULID, "--grantee-type", "account", "--grantee-id", wiringGranteeULID}, + []string{wiringRepoULID, wiringGranteeULID}, "/api/v1/repos/" + wiringRepoULID + "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/grants/account/" + wiringGranteeULID, }, { "project/by-provider", newGrantProjectRemoveCmd, - []string{wiringProjULID, "--provider", "github", "--provider-user-id", "12345"}, + []string{wiringProjULID, "github:alice"}, "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/api/v1/projects/" + wiringProjULID + "/grants/account/github/12345", }, { "project/by-grantee-id", newGrantProjectRemoveCmd, - []string{wiringProjULID, "--grantee-type", "account", "--grantee-id", wiringGranteeULID}, + []string{wiringProjULID, wiringGranteeULID}, "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/api/v1/projects/" + wiringProjULID + "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/grants/account/" + wiringGranteeULID, }, { "org/by-provider", newGrantOrgRemoveCmd, - []string{wiringOrgULID, "--provider", "github", "--provider-user-id", "12345"}, + []string{wiringOrgULID, "github:alice"}, "/api/v1/orgs/" + wiringOrgULID + "/members/github/12345", }, } @@ -67,10 +93,10 @@ func TestGrantRemove_RouteWiring(t *testing.T) { for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { var gotMethod, gotPath string - srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - gotMethod, gotPath = r.Method, r.URL.Path - w.WriteHeader(http.StatusNoContent) - })) + srv := httptest.NewServer(grantWiringHandler(t, + func(method, path string) { gotMethod, gotPath = method, path }, + func(w http.ResponseWriter) { w.WriteHeader(http.StatusNoContent) }, + )) t.Cleanup(srv.Close) _, err := runDeleteCmd(t, tc.newCmd, srv.URL, tc.args...) @@ -92,17 +118,18 @@ func TestGrantRemove_Idempotent(t *testing.T) { newCmd func() *cobra.Command args []string }{ - {"repo/by-provider", newGrantRepoRemoveCmd, []string{wiringRepoULID, "--provider", "github", "--provider-user-id", "12345"}}, - {"repo/by-grantee-id", newGrantRepoRemoveCmd, []string{wiringRepoULID, "--grantee-type", "account", "--grantee-id", wiringGranteeULID}}, - {"project/by-provider", newGrantProjectRemoveCmd, []string{wiringProjULID, "--provider", "github", "--provider-user-id", "12345"}}, - {"org/by-provider", newGrantOrgRemoveCmd, []string{wiringOrgULID, "--provider", "github", "--provider-user-id", "12345"}}, + {"repo/by-provider", newGrantRepoRemoveCmd, []string{wiringRepoULID, "github:alice"}}, + {"repo/by-grantee-id", newGrantRepoRemoveCmd, []string{wiringRepoULID, wiringGranteeULID}}, + {"project/by-provider", newGrantProjectRemoveCmd, []string{wiringProjULID, "github:alice"}}, + {"org/by-provider", newGrantOrgRemoveCmd, []string{wiringOrgULID, "github:alice"}}, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { - srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - writeNotFoundProblem(t, w) - })) + srv := httptest.NewServer(grantWiringHandler(t, + func(_, _ string) {}, + func(w http.ResponseWriter) { writeNotFoundProblem(t, w) }, + )) t.Cleanup(srv.Close) out, err := runDeleteCmd(t, tc.newCmd, srv.URL, tc.args...) diff --git a/cmd/entire/cli/repo.go b/cmd/entire/cli/repo.go index b948561253..34f3459596 100644 --- a/cmd/entire/cli/repo.go +++ b/cmd/entire/cli/repo.go @@ -46,6 +46,22 @@ func repoRow(r coreapi.Repo) []string { return []string{r.ID, r.Name, r.OwningProjectId, r.ClusterHost.Or("-"), state} } +// repoDetailColumns / repoDetailRow extend the shared repo view with the +// entire:// clone URL for the single-repo `get` output. The list view stays on +// the lean repoColumns — a full clone URL per row would bloat the table — but a +// person inspecting one repo wants the URL they can paste into `git clone` +// (COR-699). REMOTE is "-" until the repo is provisioned enough to have a +// resolvable cluster host + path. +var repoDetailColumns = []string{"ID", "NAME", "PROJECT", "CLUSTER", "STATE", "REMOTE"} + +func repoDetailRow(r coreapi.Repo) []string { + remote := repoRemoteURL(r) + if remote == "" { + remote = "-" + } + return append(repoRow(r), remote) +} + // repoRemoteURL synthesizes the entire:// clone/remote URL for a repo from // its resolved cluster host and path — the form `git clone` and // `git remote add` accept, which git-remote-entire reads back as the repo @@ -166,7 +182,7 @@ func newRepoGetCmd() *cobra.Command { Short: "Show a repository by name or ULID", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - return runCoreObject(cmd, repoColumns, repoRow, func(ctx context.Context, c *coreapi.Client) (*coreapi.Repo, error) { + return runCoreObject(cmd, repoDetailColumns, repoDetailRow, func(ctx context.Context, c *coreapi.Client) (*coreapi.Repo, error) { repoID, err := resolveRepoRef(ctx, c, args[0], project) if err != nil { return nil, err diff --git a/cmd/entire/cli/repo_test.go b/cmd/entire/cli/repo_test.go index a35e92786f..e4f477b4ad 100644 --- a/cmd/entire/cli/repo_test.go +++ b/cmd/entire/cli/repo_test.go @@ -94,6 +94,41 @@ func TestParseVisibility(t *testing.T) { } } +func TestRepoDetailRow(t *testing.T) { + t.Parallel() + + t.Run("includes the entire:// remote", func(t *testing.T) { + t.Parallel() + row := repoDetailRow(coreapi.Repo{ + ID: "01KS6KFJR2XS6PZ188MVYE07AN", + Name: "web", + OwningProjectId: "01KS6KFJR2XS6PZ188MVYE07AP", + ClusterHost: coreapi.NewOptString("aws-us-east-2.entire.io"), + Path: coreapi.NewOptString("acme/web"), + State: coreapi.NewOptRepoState(coreapi.RepoStateActive), + }) + if len(row) != len(repoDetailColumns) { + t.Fatalf("row has %d cells, want %d (one per column)", len(row), len(repoDetailColumns)) + } + if want := "entire://aws-us-east-2.entire.io/acme/web"; row[len(row)-1] != want { + t.Errorf("REMOTE cell = %q, want %q", row[len(row)-1], want) + } + }) + + t.Run("shows - when the remote is not yet resolvable", func(t *testing.T) { + t.Parallel() + row := repoDetailRow(coreapi.Repo{ + ID: "01KS6KFJR2XS6PZ188MVYE07AN", + Name: "web", + OwningProjectId: "01KS6KFJR2XS6PZ188MVYE07AP", + ClusterHost: coreapi.NewOptString("aws-us-east-2.entire.io"), + }) + if row[len(row)-1] != "-" { + t.Errorf("REMOTE cell = %q, want %q", row[len(row)-1], "-") + } + }) +} + func TestRepoCreateOutput_StampsRemote(t *testing.T) { t.Parallel() repo := &coreapi.Repo{ diff --git a/cmd/entire/cli/resolveref.go b/cmd/entire/cli/resolveref.go index ae90a2bf9f..d89dcd68ca 100644 --- a/cmd/entire/cli/resolveref.go +++ b/cmd/entire/cli/resolveref.go @@ -20,6 +20,13 @@ import ( // under the response's singular `org`/`project` field, or 404) — the CLI never // lists everything and filters client-side. +// providerGitHub is the identity-provider slug for GitHub-backed accounts, the +// provider half of a qualified grantee handle like "github:alice". GitHub is the +// only provider with backing accounts today; other slugs resolve once they exist +// server-side. (Distinct from setup.go's checkpointProviderGitHub, which names +// the checkpoint hosting provider — same string, unrelated concern.) +const providerGitHub = "github" + // looksLikeULID reports whether s has the shape of a ULID: 26 characters drawn // from Crockford base32 (digits plus uppercase letters, excluding I, L, O, U). // The check is shape-only and case-insensitive on the alphabet; it never hits @@ -95,6 +102,39 @@ func resolveAccountRef(ctx context.Context, c *coreapi.Client, ref string) (stri return id.AccountId, nil } +// resolveGranteeProvider turns a grantee reference into the (provider, +// providerUserId) pair the grant/membership "by provider" routes key on. The +// reference is a provider-qualified handle (e.g. "github:alice"); it is +// resolved through the control plane to the provider's stable numeric user id. +// The friendly handle alone is not what the grant routes accept — passing it as +// --provider-user-id was the COR-699 footgun ("provider identity not found") — +// so the CLI always resolves it first. A bare account ULID is rejected here: +// the by-provider routes can't be addressed by ULID, and there is no reverse +// account→provider-id lookup; callers that accept a ULID grantee (project/repo +// remove) handle it via the typed-id route before reaching this helper. +func resolveGranteeProvider(ctx context.Context, c *coreapi.Client, ref string) (provider, providerUserID string, err error) { + p, handle, err := parseQualifiedHandle(ref) + if err != nil { + return "", "", err + } + id, err := c.ResolveHandle(ctx, coreapi.ResolveHandleParams{Provider: p, Handle: handle}) + if err != nil { + if isCoreNotFound(err) { + return "", "", fmt.Errorf("no %s identity for handle %q", p, handle) + } + return "", "", err + } + if id.ProviderUserId == "" { + return "", "", fmt.Errorf("handle %q resolved to no provider user id", ref) + } + // Prefer the server-normalized provider over the raw prefix, falling back to + // the input when the response omits it. + if id.Provider != "" { + p = id.Provider + } + return p, id.ProviderUserId, nil +} + // parseQualifiedHandle splits a provider-qualified handle like "github:alice" // into its provider ("github") and handle ("alice"). Accounts are addressed by // this friendly form; a value with no "provider:" prefix is rejected so the diff --git a/cmd/entire/cli/resolveref_test.go b/cmd/entire/cli/resolveref_test.go index abed6b186b..22d756efbf 100644 --- a/cmd/entire/cli/resolveref_test.go +++ b/cmd/entire/cli/resolveref_test.go @@ -308,6 +308,55 @@ func TestResolveAccountRef(t *testing.T) { }) } +func TestResolveGranteeProvider(t *testing.T) { + t.Parallel() + + t.Run("handle resolves to the provider user id in one call", func(t *testing.T) { + t.Parallel() + c, calls := resolveTestClient(t, func(w http.ResponseWriter, _ *http.Request) { + if err := writeJSON(w, &coreapi.ResolvedIdentity{AccountId: ulidResolvedAcct, Provider: providerGitHub, Handle: "alice", ProviderUserId: "12345"}); err != nil { + t.Errorf("encode identity: %v", err) + } + }) + provider, puid, err := resolveGranteeProvider(context.Background(), c, "github:alice") + if err != nil { + t.Fatalf("resolveGranteeProvider: %v", err) + } + if provider != providerGitHub || puid != "12345" { + t.Errorf("resolveGranteeProvider = (%q, %q), want (github, 12345)", provider, puid) + } + if n := calls.Load(); n != 1 { + t.Errorf("handle ref made %d HTTP calls, want 1", n) + } + }) + + t.Run("non-qualified handle fails before any network call", func(t *testing.T) { + t.Parallel() + c, calls := resolveTestClient(t, func(w http.ResponseWriter, _ *http.Request) { + t.Error("unexpected HTTP call for an invalid handle") + w.WriteHeader(http.StatusInternalServerError) + }) + if _, _, err := resolveGranteeProvider(context.Background(), c, "alice"); err == nil { + t.Error("resolveGranteeProvider expected error for non-qualified handle") + } + if n := calls.Load(); n != 0 { + t.Errorf("invalid handle made %d HTTP calls, want 0", n) + } + }) + + t.Run("empty provider user id is an error", func(t *testing.T) { + t.Parallel() + c, _ := resolveTestClient(t, func(w http.ResponseWriter, _ *http.Request) { + if err := writeJSON(w, &coreapi.ResolvedIdentity{AccountId: ulidResolvedAcct, Provider: providerGitHub, Handle: "alice", ProviderUserId: ""}); err != nil { + t.Errorf("encode identity: %v", err) + } + }) + if _, _, err := resolveGranteeProvider(context.Background(), c, "github:alice"); err == nil { + t.Error("resolveGranteeProvider expected error for empty provider user id") + } + }) +} + func TestLooksLikeULID(t *testing.T) { t.Parallel() tests := []struct { From 9fe0c77eb688f1e609d0c58dc68b7011565d1bb4 Mon Sep 17 00:00:00 2001 From: paul <423357+toothbrush@users.noreply.github.com> Date: Sun, 28 Jun 2026 18:28:15 +0930 Subject: [PATCH 2/5] fix(grant): resolve repo by name via the singular `repo` field (COR-699) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The control plane returns a name-filtered repo list under the singular `repo` field (like org/project), not the plural `repos` array — `repos` is only populated for an unfiltered page. resolveRepoRef read `repos`, so `grant repo {list,add,remove} --project

` always 404'd with "no repo named" even when the repo existed. The fixture mocked the plural array too, hiding it; it now mirrors the real server's singular field. Co-Authored-By: Claude Opus 4.8 (1M context) Entire-Checkpoint: 0a7fba82dafb --- cmd/entire/cli/resolveref.go | 8 ++++---- cmd/entire/cli/resolveref_test.go | 7 +++++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/cmd/entire/cli/resolveref.go b/cmd/entire/cli/resolveref.go index d89dcd68ca..213c1e6d15 100644 --- a/cmd/entire/cli/resolveref.go +++ b/cmd/entire/cli/resolveref.go @@ -172,10 +172,10 @@ func resolveProjectRef(ctx context.Context, c *coreapi.Client, ref string) (stri // resolveRepoRef turns a repo reference into its ULID. A ULID passes through. // A name requires a project scope (projectRef, itself a name or ULID) because // repo names are unique only within a project: the repo is resolved via the -// server's case-insensitive by-name lookup, scoped to that project. A -// name-filtered query returns the single match in the response's `repo` -// field (empty when there's no match) — the `repos` array is only populated -// for unfiltered list pages. +// server's case-insensitive by-name lookup, scoped to that project. Like the +// org/project endpoints, a name-filtered list returns the single match under the +// response's singular `repo` field (the plural `repos` is only populated for an +// unfiltered page) — reading `repos` here was the COR-699 bug. func resolveRepoRef(ctx context.Context, c *coreapi.Client, ref, projectRef string) (string, error) { if looksLikeULID(ref) { return ref, nil diff --git a/cmd/entire/cli/resolveref_test.go b/cmd/entire/cli/resolveref_test.go index 22d756efbf..a36d26f76a 100644 --- a/cmd/entire/cli/resolveref_test.go +++ b/cmd/entire/cli/resolveref_test.go @@ -204,8 +204,11 @@ func TestResolveRepoRef(t *testing.T) { var gotName string c, calls := resolveTestClient(t, func(w http.ResponseWriter, r *http.Request) { gotName = r.URL.Query().Get("name") - // A name-filtered query returns the match in the singular `repo` - // field, not the `repos` page array — mirror the real server. + // A name-filtered list returns the single match under the singular + // `repo` field (like org/project) — NOT the plural `repos` array, + // which is only populated for an unfiltered page. Reading `repos` + // here was the COR-699 bug, so the fixture must mirror the real + // server's singular field to keep that regression covered. if err := writeJSON(w, &coreapi.ListProjectReposOutputBody{Repo: coreapi.NewOptRepo(coreapi.Repo{ID: ulidRepoWeb, Name: "web"})}); err != nil { t.Errorf("encode repo: %v", err) } From 295e3012063496f1516cd30d0ee376ef3f2d21e7 Mon Sep 17 00:00:00 2001 From: paul <423357+toothbrush@users.noreply.github.com> Date: Sun, 28 Jun 2026 18:44:32 +0930 Subject: [PATCH 3/5] feat(grant): show friendly names, source, and effective grants in list output MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `entire grant repo list` / `project members` now render GRANTEE (handle or org name), keep ID (ULID) for revoke, and add SOURCE so inherited and owner grants are distinguishable from direct ones — matching the expanded server response. Spec patched for the two new RepoGrant/ProjectGrant fields (granteeName, source) and the ogen client regenerated. Co-Authored-By: Claude Opus 4.8 (1M context) --- cmd/entire/cli/grant.go | 29 +++++--- internal/coreapi/oas_json_gen.go | 92 +++++++++++++++++++++---- internal/coreapi/oas_schemas_gen.go | 56 +++++++++++++-- internal/coreapi/spec/core.gen.json | 18 ++++- internal/coreapi/spec/core.openapi.json | 2 +- 5 files changed, 167 insertions(+), 30 deletions(-) diff --git a/cmd/entire/cli/grant.go b/cmd/entire/cli/grant.go index 09b8b25701..653e08ffe3 100644 --- a/cmd/entire/cli/grant.go +++ b/cmd/entire/cli/grant.go @@ -63,11 +63,13 @@ func newGrantCmd() *cobra.Command { return cmd } -// orgMemberColumns / projectGrantColumns are the human table views of the -// two membership/grant listings. +// orgMemberColumns / grantColumns are the human table views of the +// membership/grant listings. Grant listings now include inherited and owner +// grants, so GRANTEE shows a friendly name (handle/org name) with SOURCE +// saying where the grant comes from; ID keeps the ULID for revoke. var ( - orgMemberColumns = []string{"ACCOUNT", "ROLE", "STATUS"} - projectGrantColumns = []string{"GRANTEE-TYPE", "GRANTEE", "ROLE"} + orgMemberColumns = []string{"ACCOUNT", "ROLE", "STATUS"} + grantColumns = []string{"GRANTEE-TYPE", "GRANTEE", "ID", "ROLE", "SOURCE"} ) func orgMemberRow(m coreapi.Membership) []string { @@ -75,13 +77,22 @@ func orgMemberRow(m coreapi.Membership) []string { } func projectGrantRow(g coreapi.ProjectGrant) []string { - return []string{g.GranteeType, g.GranteeId, g.Role} + return []string{g.GranteeType, granteeName(g.GranteeName, g.GranteeId), g.GranteeId, g.Role, g.Source} } // repoGrantRow mirrors projectGrantRow; RepoGrant and ProjectGrant share the -// grantee-type/grantee/role shape, so both reuse projectGrantColumns. +// grantee/role/source shape, so both reuse grantColumns. func repoGrantRow(g coreapi.RepoGrant) []string { - return []string{g.GranteeType, g.GranteeId, g.Role} + return []string{g.GranteeType, granteeName(g.GranteeName, g.GranteeId), g.GranteeId, g.Role, g.Source} +} + +// granteeName returns the friendly name when the server resolved one, falling +// back to the ULID for grantees it couldn't label (e.g. teams). +func granteeName(name coreapi.OptString, granteeID string) string { + if n := name.Or(""); n != "" { + return n + } + return granteeID } // --- org membership ------------------------------------------------------- @@ -246,7 +257,7 @@ func newGrantProjectListCmd() *cobra.Command { Short: "List project members", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - return runCoreList(cmd, projectGrantColumns, projectGrantRow, func(ctx context.Context, c *coreapi.Client) ([]coreapi.ProjectGrant, error) { + return runCoreList(cmd, grantColumns, projectGrantRow, func(ctx context.Context, c *coreapi.Client) ([]coreapi.ProjectGrant, error) { projID, err := resolveProjectRef(ctx, c, args[0]) if err != nil { return nil, err @@ -374,7 +385,7 @@ func newGrantRepoListCmd() *cobra.Command { Short: "List repo grants", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - return runCoreList(cmd, projectGrantColumns, repoGrantRow, func(ctx context.Context, c *coreapi.Client) ([]coreapi.RepoGrant, error) { + return runCoreList(cmd, grantColumns, repoGrantRow, func(ctx context.Context, c *coreapi.Client) ([]coreapi.RepoGrant, error) { repoID, err := resolveRepoRef(ctx, c, args[0], project) if err != nil { return nil, err diff --git a/internal/coreapi/oas_json_gen.go b/internal/coreapi/oas_json_gen.go index 35e026d07a..5db8370280 100644 --- a/internal/coreapi/oas_json_gen.go +++ b/internal/coreapi/oas_json_gen.go @@ -14909,6 +14909,12 @@ func (s *ProjectGrant) encodeFields(e *jx.Encoder) { e.FieldStart("granteeId") e.Str(s.GranteeId) } + { + if s.GranteeName.Set { + e.FieldStart("granteeName") + s.GranteeName.Encode(e) + } + } { e.FieldStart("granteeType") e.Str(s.GranteeType) @@ -14917,6 +14923,10 @@ func (s *ProjectGrant) encodeFields(e *jx.Encoder) { e.FieldStart("role") e.Str(s.Role) } + { + e.FieldStart("source") + e.Str(s.Source) + } for k, elem := range s.AdditionalProps { e.FieldStart(k) @@ -14926,10 +14936,12 @@ func (s *ProjectGrant) encodeFields(e *jx.Encoder) { } } -var jsonFieldsNameOfProjectGrant = [3]string{ +var jsonFieldsNameOfProjectGrant = [5]string{ 0: "granteeId", - 1: "granteeType", - 2: "role", + 1: "granteeName", + 2: "granteeType", + 3: "role", + 4: "source", } // Decode decodes ProjectGrant from json. @@ -14954,8 +14966,18 @@ func (s *ProjectGrant) Decode(d *jx.Decoder) error { }(); err != nil { return errors.Wrap(err, "decode field \"granteeId\"") } + case "granteeName": + if err := func() error { + s.GranteeName.Reset() + if err := s.GranteeName.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"granteeName\"") + } case "granteeType": - requiredBitSet[0] |= 1 << 1 + requiredBitSet[0] |= 1 << 2 if err := func() error { v, err := d.Str() s.GranteeType = string(v) @@ -14967,7 +14989,7 @@ func (s *ProjectGrant) Decode(d *jx.Decoder) error { return errors.Wrap(err, "decode field \"granteeType\"") } case "role": - requiredBitSet[0] |= 1 << 2 + requiredBitSet[0] |= 1 << 3 if err := func() error { v, err := d.Str() s.Role = string(v) @@ -14978,6 +15000,18 @@ func (s *ProjectGrant) Decode(d *jx.Decoder) error { }(); err != nil { return errors.Wrap(err, "decode field \"role\"") } + case "source": + requiredBitSet[0] |= 1 << 4 + if err := func() error { + v, err := d.Str() + s.Source = string(v) + if err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"source\"") + } default: var elem jx.Raw if err := func() error { @@ -14999,7 +15033,7 @@ func (s *ProjectGrant) Decode(d *jx.Decoder) error { // Validate required fields. var failures []validate.FieldError for i, mask := range [1]uint8{ - 0b00000111, + 0b00011101, } { if result := (requiredBitSet[i] & mask) ^ mask; result != 0 { // Mask only required fields and check equality to mask using XOR. @@ -15551,6 +15585,12 @@ func (s *RepoGrant) encodeFields(e *jx.Encoder) { e.FieldStart("granteeId") e.Str(s.GranteeId) } + { + if s.GranteeName.Set { + e.FieldStart("granteeName") + s.GranteeName.Encode(e) + } + } { e.FieldStart("granteeType") e.Str(s.GranteeType) @@ -15559,6 +15599,10 @@ func (s *RepoGrant) encodeFields(e *jx.Encoder) { e.FieldStart("role") e.Str(s.Role) } + { + e.FieldStart("source") + e.Str(s.Source) + } for k, elem := range s.AdditionalProps { e.FieldStart(k) @@ -15568,10 +15612,12 @@ func (s *RepoGrant) encodeFields(e *jx.Encoder) { } } -var jsonFieldsNameOfRepoGrant = [3]string{ +var jsonFieldsNameOfRepoGrant = [5]string{ 0: "granteeId", - 1: "granteeType", - 2: "role", + 1: "granteeName", + 2: "granteeType", + 3: "role", + 4: "source", } // Decode decodes RepoGrant from json. @@ -15596,8 +15642,18 @@ func (s *RepoGrant) Decode(d *jx.Decoder) error { }(); err != nil { return errors.Wrap(err, "decode field \"granteeId\"") } + case "granteeName": + if err := func() error { + s.GranteeName.Reset() + if err := s.GranteeName.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"granteeName\"") + } case "granteeType": - requiredBitSet[0] |= 1 << 1 + requiredBitSet[0] |= 1 << 2 if err := func() error { v, err := d.Str() s.GranteeType = string(v) @@ -15609,7 +15665,7 @@ func (s *RepoGrant) Decode(d *jx.Decoder) error { return errors.Wrap(err, "decode field \"granteeType\"") } case "role": - requiredBitSet[0] |= 1 << 2 + requiredBitSet[0] |= 1 << 3 if err := func() error { v, err := d.Str() s.Role = string(v) @@ -15620,6 +15676,18 @@ func (s *RepoGrant) Decode(d *jx.Decoder) error { }(); err != nil { return errors.Wrap(err, "decode field \"role\"") } + case "source": + requiredBitSet[0] |= 1 << 4 + if err := func() error { + v, err := d.Str() + s.Source = string(v) + if err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"source\"") + } default: var elem jx.Raw if err := func() error { @@ -15641,7 +15709,7 @@ func (s *RepoGrant) Decode(d *jx.Decoder) error { // Validate required fields. var failures []validate.FieldError for i, mask := range [1]uint8{ - 0b00000111, + 0b00011101, } { if result := (requiredBitSet[i] & mask) ^ mask; result != 0 { // Mask only required fields and check equality to mask using XOR. diff --git a/internal/coreapi/oas_schemas_gen.go b/internal/coreapi/oas_schemas_gen.go index 5252dbf810..8a07726b10 100644 --- a/internal/coreapi/oas_schemas_gen.go +++ b/internal/coreapi/oas_schemas_gen.go @@ -6439,9 +6439,11 @@ func (s *ProjectAdditional) init() ProjectAdditional { // Ref: #/components/schemas/ProjectGrant type ProjectGrant struct { - GranteeId string `json:"granteeId"` - GranteeType string `json:"granteeType"` - Role string `json:"role"` + GranteeId string `json:"granteeId"` + GranteeName OptString `json:"granteeName"` + GranteeType string `json:"granteeType"` + Role string `json:"role"` + Source string `json:"source"` AdditionalProps ProjectGrantAdditional } @@ -6450,6 +6452,11 @@ func (s *ProjectGrant) GetGranteeId() string { return s.GranteeId } +// GetGranteeName returns the value of GranteeName. +func (s *ProjectGrant) GetGranteeName() OptString { + return s.GranteeName +} + // GetGranteeType returns the value of GranteeType. func (s *ProjectGrant) GetGranteeType() string { return s.GranteeType @@ -6460,6 +6467,11 @@ func (s *ProjectGrant) GetRole() string { return s.Role } +// GetSource returns the value of Source. +func (s *ProjectGrant) GetSource() string { + return s.Source +} + // GetAdditionalProps returns the value of AdditionalProps. func (s *ProjectGrant) GetAdditionalProps() ProjectGrantAdditional { return s.AdditionalProps @@ -6470,6 +6482,11 @@ func (s *ProjectGrant) SetGranteeId(val string) { s.GranteeId = val } +// SetGranteeName sets the value of GranteeName. +func (s *ProjectGrant) SetGranteeName(val OptString) { + s.GranteeName = val +} + // SetGranteeType sets the value of GranteeType. func (s *ProjectGrant) SetGranteeType(val string) { s.GranteeType = val @@ -6480,6 +6497,11 @@ func (s *ProjectGrant) SetRole(val string) { s.Role = val } +// SetSource sets the value of Source. +func (s *ProjectGrant) SetSource(val string) { + s.Source = val +} + // SetAdditionalProps sets the value of AdditionalProps. func (s *ProjectGrant) SetAdditionalProps(val ProjectGrantAdditional) { s.AdditionalProps = val @@ -6723,9 +6745,11 @@ func (s *RepoAdditional) init() RepoAdditional { // Ref: #/components/schemas/RepoGrant type RepoGrant struct { - GranteeId string `json:"granteeId"` - GranteeType string `json:"granteeType"` - Role string `json:"role"` + GranteeId string `json:"granteeId"` + GranteeName OptString `json:"granteeName"` + GranteeType string `json:"granteeType"` + Role string `json:"role"` + Source string `json:"source"` AdditionalProps RepoGrantAdditional } @@ -6734,6 +6758,11 @@ func (s *RepoGrant) GetGranteeId() string { return s.GranteeId } +// GetGranteeName returns the value of GranteeName. +func (s *RepoGrant) GetGranteeName() OptString { + return s.GranteeName +} + // GetGranteeType returns the value of GranteeType. func (s *RepoGrant) GetGranteeType() string { return s.GranteeType @@ -6744,6 +6773,11 @@ func (s *RepoGrant) GetRole() string { return s.Role } +// GetSource returns the value of Source. +func (s *RepoGrant) GetSource() string { + return s.Source +} + // GetAdditionalProps returns the value of AdditionalProps. func (s *RepoGrant) GetAdditionalProps() RepoGrantAdditional { return s.AdditionalProps @@ -6754,6 +6788,11 @@ func (s *RepoGrant) SetGranteeId(val string) { s.GranteeId = val } +// SetGranteeName sets the value of GranteeName. +func (s *RepoGrant) SetGranteeName(val OptString) { + s.GranteeName = val +} + // SetGranteeType sets the value of GranteeType. func (s *RepoGrant) SetGranteeType(val string) { s.GranteeType = val @@ -6764,6 +6803,11 @@ func (s *RepoGrant) SetRole(val string) { s.Role = val } +// SetSource sets the value of Source. +func (s *RepoGrant) SetSource(val string) { + s.Source = val +} + // SetAdditionalProps sets the value of AdditionalProps. func (s *RepoGrant) SetAdditionalProps(val RepoGrantAdditional) { s.AdditionalProps = val diff --git a/internal/coreapi/spec/core.gen.json b/internal/coreapi/spec/core.gen.json index 4470e34b06..fc0320c6ae 100644 --- a/internal/coreapi/spec/core.gen.json +++ b/internal/coreapi/spec/core.gen.json @@ -1844,17 +1844,24 @@ "granteeId": { "type": "string" }, + "granteeName": { + "type": "string" + }, "granteeType": { "type": "string" }, "role": { "type": "string" + }, + "source": { + "type": "string" } }, "required": [ "granteeType", "granteeId", - "role" + "role", + "source" ], "type": "object" }, @@ -1937,17 +1944,24 @@ "granteeId": { "type": "string" }, + "granteeName": { + "type": "string" + }, "granteeType": { "type": "string" }, "role": { "type": "string" + }, + "source": { + "type": "string" } }, "required": [ "granteeType", "granteeId", - "role" + "role", + "source" ], "type": "object" }, diff --git a/internal/coreapi/spec/core.openapi.json b/internal/coreapi/spec/core.openapi.json index bed43e0a22..d1ed445f61 100644 --- a/internal/coreapi/spec/core.openapi.json +++ b/internal/coreapi/spec/core.openapi.json @@ -1 +1 @@ -{"components":{"schemas":{"AddOrgMemberInputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/AddOrgMemberInputBody.json"],"format":"uri","readOnly":true,"type":"string"},"provider":{"minLength":1,"type":"string"},"providerUserId":{"minLength":1,"type":"string"},"role":{"default":"member","description":"Role at the org; defaults to member.","enum":["owner","admin","member"],"type":"string"}},"required":["provider","providerUserId"],"type":"object"},"AuditEvent":{"additionalProperties":true,"properties":{"actorId":{"type":"string"},"eventType":{"type":"string"},"id":{"type":"string"},"ipAddress":{"description":"Source IP recorded when the event was logged.","type":"string"},"metadata":{"additionalProperties":{},"type":"object"},"occurredAt":{"format":"date-time","type":"string"}},"required":["id","occurredAt","eventType","actorId"],"type":"object"},"AvailableMirror":{"additionalProperties":true,"properties":{"access":{"description":"Caller's effective GitHub access: read, write, or admin.","enum":["read","write","admin"],"type":"string"},"isArchived":{"type":"boolean"},"isPrivate":{"type":"boolean"},"owner":{"type":"string"},"repo":{"type":"string"},"status":{"description":"available (can onboard), mirrored (already mirrored), or owner-only (personal repo of another user).","enum":["available","mirrored","owner-only"],"type":"string"}},"required":["owner","repo","access","status"],"type":"object"},"BatchLookupInputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/BatchLookupInputBody.json"],"format":"uri","readOnly":true,"type":"string"},"refs":{"items":{"$ref":"#/components/schemas/LookupRef"},"maxItems":100,"minItems":1,"type":"array"}},"required":["refs"],"type":"object"},"BatchLookupOutputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/BatchLookupOutputBody.json"],"format":"uri","readOnly":true,"type":"string"},"refs":{"items":{"$ref":"#/components/schemas/LookupRefResult"},"type":"array"}},"required":["refs"],"type":"object"},"Binding":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/Binding.json"],"format":"uri","readOnly":true,"type":"string"},"accountId":{"type":"string"},"attributeFilter":{},"createdAt":{"format":"date-time","type":"string"},"id":{"type":"string"},"providerId":{"type":"string"}},"required":["id","accountId","providerId","attributeFilter","createdAt"],"type":"object"},"Cluster":{"additionalProperties":true,"properties":{"apiUrl":{"type":"string"},"isDefault":{"type":"boolean"},"jurisdiction":{"type":"string"},"publicUrl":{"type":"string"},"slug":{"type":"string"}},"required":["slug","jurisdiction","publicUrl","isDefault"],"type":"object"},"CreateBindingInputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/CreateBindingInputBody.json"],"format":"uri","readOnly":true,"type":"string"},"attributeFilter":{"description":"Exact-match key/value map; empty filter matches any token."},"providerId":{"minLength":1,"type":"string"}},"required":["providerId"],"type":"object"},"CreateMirrorInputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/CreateMirrorInputBody.json"],"format":"uri","readOnly":true,"type":"string"},"clusterHost":{"description":"DNS host of the destination cluster.","minLength":1,"type":"string"},"owner":{"minLength":1,"type":"string"},"provider":{"enum":["github"],"type":"string"},"repo":{"minLength":1,"type":"string"}},"required":["provider","owner","repo","clusterHost"],"type":"object"},"CreateOrgInputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/CreateOrgInputBody.json"],"format":"uri","readOnly":true,"type":"string"},"name":{"description":"Display name.","maxLength":100,"minLength":1,"type":"string"},"region":{"description":"Jurisdiction slug; defaults to the server's home jurisdiction.","type":"string"}},"required":["name"],"type":"object"},"CreateProjectInputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/CreateProjectInputBody.json"],"format":"uri","readOnly":true,"type":"string"},"name":{"maxLength":100,"minLength":1,"type":"string"},"ownerId":{"minLength":1,"type":"string"},"ownerType":{"enum":["org","account"],"type":"string"},"region":{"type":"string"}},"required":["name","ownerType","ownerId"],"type":"object"},"CreateRepoInputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/CreateRepoInputBody.json"],"format":"uri","readOnly":true,"type":"string"},"clusterHost":{"description":"Public host of the cluster to pin the repo to (e.g. royalcanin.partial.to); empty lands on the jurisdiction default.","type":"string"},"name":{"minLength":1,"type":"string"},"objectFormat":{"description":"Hash format; defaults to sha1.","enum":["sha1","sha256"],"type":"string"},"projectId":{"pattern":"^[0-9A-HJKMNP-TV-Z]{26}$","type":"string"}},"required":["projectId","name"],"type":"object"},"CreateServiceAccountInputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/CreateServiceAccountInputBody.json"],"format":"uri","readOnly":true,"type":"string"},"name":{"minLength":1,"type":"string"},"orgId":{"pattern":"^[0-9A-HJKMNP-TV-Z]{26}$","type":"string"}},"required":["orgId","name"],"type":"object"},"CreatedMirror":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/CreatedMirror.json"],"format":"uri","readOnly":true,"type":"string"},"created":{"description":"true on fresh creation; false when an existing mirror was returned.","type":"boolean"},"empty":{"description":"true when the upstream has no refs to clone.","type":"boolean"},"mirrorId":{"type":"string"},"mirrorUrl":{"type":"string"},"publicUrl":{"type":"string"}},"required":["mirrorId","mirrorUrl","publicUrl","created","empty"],"type":"object"},"ErrorDetail":{"additionalProperties":true,"properties":{"location":{"description":"Where the error occurred, e.g. 'body.items[3].tags' or 'path.thing-id'","type":"string"},"message":{"description":"Error message text","type":"string"},"value":{"description":"The value at the given location"}},"type":"object"},"ErrorModel":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/ErrorModel.json"],"format":"uri","readOnly":true,"type":"string"},"detail":{"description":"A human-readable explanation specific to this occurrence of the problem.","examples":["Property foo is required but is missing."],"type":"string"},"errors":{"description":"Optional list of individual error details","items":{"$ref":"#/components/schemas/ErrorDetail"},"type":"array"},"instance":{"description":"A URI reference that identifies the specific occurrence of the problem.","examples":["https://example.com/error-log/abc123"],"format":"uri","type":"string"},"status":{"description":"HTTP status code","examples":[400],"format":"int64","type":"integer"},"title":{"description":"A short, human-readable summary of the problem type. This value should not change between occurrences of the error.","examples":["Bad Request"],"type":"string"},"type":{"default":"about:blank","description":"A URI reference to human-readable documentation for the error.","examples":["https://example.com/errors/example"],"format":"uri","type":"string"}},"type":"object"},"GetMeOutputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/GetMeOutputBody.json"],"format":"uri","readOnly":true,"type":"string"},"auth":{"$ref":"#/components/schemas/MeAuth"},"global":{"$ref":"#/components/schemas/MeGlobal"},"jurisdiction":{"type":"string"},"mode":{"enum":["standalone","global","regional"],"type":"string"},"regional":{"$ref":"#/components/schemas/MeRegional"},"regionalUnavailable":{"$ref":"#/components/schemas/MeRegionalUnavailable"}},"required":["global","auth"],"type":"object"},"GetPermissionsOutputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/GetPermissionsOutputBody.json"],"format":"uri","readOnly":true,"type":"string"},"explain":{"additionalProperties":{},"type":"object"},"permissions":{"items":{"type":"string"},"type":"array"},"resourceId":{"type":"string"},"resourceType":{"type":"string"}},"required":["resourceType","resourceId"],"type":"object"},"GetRepoVisibilityOutputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/GetRepoVisibilityOutputBody.json"],"format":"uri","readOnly":true,"type":"string"},"visibility":{"enum":["public","private"],"type":"string"}},"required":["visibility"],"type":"object"},"GetVersionOutputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/GetVersionOutputBody.json"],"format":"uri","readOnly":true,"type":"string"},"mode":{"description":"Server mode.","enum":["standalone","global","regional"],"type":"string"},"version":{"description":"Git commit SHA of the running entire-core binary, or \"dev\" for an untagged local build.","type":"string"}},"required":["version"],"type":"object"},"GrantMirrorCollaboratorInputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/GrantMirrorCollaboratorInputBody.json"],"format":"uri","readOnly":true,"type":"string"},"clusterHost":{"description":"Public host of the cluster serving the mirror.","minLength":1,"type":"string"},"handle":{"description":"Qualified grantee handle, e.g. github:alice.","minLength":1,"type":"string"},"owner":{"minLength":1,"type":"string"},"provider":{"enum":["github"],"type":"string"},"repo":{"minLength":1,"type":"string"},"role":{"description":"Grant level: reader (pull) or writer (pull+push).","enum":["reader","writer"],"type":"string"}},"required":["provider","owner","repo","clusterHost","handle","role"],"type":"object"},"GrantProjectAccessInputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/GrantProjectAccessInputBody.json"],"format":"uri","readOnly":true,"type":"string"},"granteeType":{"default":"account","enum":["account"],"type":"string"},"provider":{"minLength":1,"type":"string"},"providerUserId":{"minLength":1,"type":"string"},"role":{"enum":["reader","writer","admin"],"type":"string"}},"required":["provider","providerUserId","role"],"type":"object"},"GrantProjectAccessOutputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/GrantProjectAccessOutputBody.json"],"format":"uri","readOnly":true,"type":"string"},"status":{"type":"string"}},"required":["status"],"type":"object"},"GrantRepoAccessInputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/GrantRepoAccessInputBody.json"],"format":"uri","readOnly":true,"type":"string"},"granteeType":{"default":"account","enum":["account"],"type":"string"},"provider":{"minLength":1,"type":"string"},"providerUserId":{"minLength":1,"type":"string"},"role":{"enum":["reader","writer","admin"],"type":"string"}},"required":["provider","providerUserId","role"],"type":"object"},"GrantRepoAccessOutputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/GrantRepoAccessOutputBody.json"],"format":"uri","readOnly":true,"type":"string"},"status":{"type":"string"}},"required":["status"],"type":"object"},"GrantServiceAccountAccessInputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/GrantServiceAccountAccessInputBody.json"],"format":"uri","readOnly":true,"type":"string"},"resourceId":{"minLength":1,"type":"string"},"resourceType":{"enum":["repo","project"],"type":"string"},"role":{"enum":["reader","writer","admin"],"type":"string"}},"required":["resourceType","resourceId","role"],"type":"object"},"GrantServiceAccountAccessOutputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/GrantServiceAccountAccessOutputBody.json"],"format":"uri","readOnly":true,"type":"string"},"status":{"type":"string"}},"required":["status"],"type":"object"},"GrantedMirrorCollaborator":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/GrantedMirrorCollaborator.json"],"format":"uri","readOnly":true,"type":"string"},"accountId":{"description":"Entire account the grant was written for.","type":"string"},"role":{"type":"string"}},"required":["accountId","role"],"type":"object"},"ListAuditEventsOutputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/ListAuditEventsOutputBody.json"],"format":"uri","readOnly":true,"type":"string"},"events":{"items":{"$ref":"#/components/schemas/AuditEvent"},"type":"array"},"nextPageToken":{"description":"Pass back to fetch the next page; empty when no more entries.","type":"string"}},"required":["events"],"type":"object"},"ListAvailableMirrorsOutputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/ListAvailableMirrorsOutputBody.json"],"format":"uri","readOnly":true,"type":"string"},"available":{"items":{"$ref":"#/components/schemas/AvailableMirror"},"type":"array"}},"required":["available"],"type":"object"},"ListBindingsOutputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/ListBindingsOutputBody.json"],"format":"uri","readOnly":true,"type":"string"},"bindings":{"items":{"$ref":"#/components/schemas/Binding"},"type":"array"},"nextPageToken":{"description":"Pass back to fetch the next page; empty when no more entries.","type":"string"}},"required":["bindings"],"type":"object"},"ListClustersOutputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/ListClustersOutputBody.json"],"format":"uri","readOnly":true,"type":"string"},"clusters":{"items":{"$ref":"#/components/schemas/Cluster"},"type":"array"}},"required":["clusters"],"type":"object"},"ListMirrorCollaboratorsOutputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/ListMirrorCollaboratorsOutputBody.json"],"format":"uri","readOnly":true,"type":"string"},"collaborators":{"items":{"$ref":"#/components/schemas/MirrorCollaborator"},"type":"array"}},"required":["collaborators"],"type":"object"},"ListMirrorsOutputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/ListMirrorsOutputBody.json"],"format":"uri","readOnly":true,"type":"string"},"mirrors":{"items":{"$ref":"#/components/schemas/Mirror"},"type":"array"},"nextPageToken":{"description":"Pass back to fetch the next page; empty when no more entries.","type":"string"}},"required":["mirrors"],"type":"object"},"ListOIDCProvidersOutputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/ListOIDCProvidersOutputBody.json"],"format":"uri","readOnly":true,"type":"string"},"nextPageToken":{"description":"Pass back to fetch the next page; empty when no more entries.","type":"string"},"providers":{"items":{"$ref":"#/components/schemas/OIDCProvider"},"type":"array"}},"required":["providers"],"type":"object"},"ListOrgMembersOutputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/ListOrgMembersOutputBody.json"],"format":"uri","readOnly":true,"type":"string"},"members":{"items":{"$ref":"#/components/schemas/Membership"},"type":"array"},"nextPageToken":{"description":"Pass back to fetch the next page; empty when no more entries.","type":"string"}},"required":["members"],"type":"object"},"ListOrgProjectsOutputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/ListOrgProjectsOutputBody.json"],"format":"uri","readOnly":true,"type":"string"},"nextPageToken":{"description":"Pass back to fetch the next page; empty when no more entries.","type":"string"},"project":{"$ref":"#/components/schemas/Project"},"projects":{"items":{"$ref":"#/components/schemas/Project"},"type":"array"}},"type":"object"},"ListOrgsOutputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/ListOrgsOutputBody.json"],"format":"uri","readOnly":true,"type":"string"},"nextPageToken":{"description":"Pass back to fetch the next page; empty when no more entries.","type":"string"},"org":{"$ref":"#/components/schemas/Org"},"orgs":{"items":{"$ref":"#/components/schemas/Org"},"type":"array"}},"type":"object"},"ListProjectMembersOutputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/ListProjectMembersOutputBody.json"],"format":"uri","readOnly":true,"type":"string"},"members":{"items":{"$ref":"#/components/schemas/ProjectGrant"},"type":"array"},"nextPageToken":{"description":"Pass back to fetch the next page; empty when no more entries.","type":"string"}},"required":["members"],"type":"object"},"ListProjectReposOutputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/ListProjectReposOutputBody.json"],"format":"uri","readOnly":true,"type":"string"},"nextPageToken":{"description":"Pass back to fetch the next page; empty when no more entries.","type":"string"},"repo":{"$ref":"#/components/schemas/Repo"},"repos":{"items":{"$ref":"#/components/schemas/Repo"},"type":"array"}},"type":"object"},"ListProjectsOutputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/ListProjectsOutputBody.json"],"format":"uri","readOnly":true,"type":"string"},"nextPageToken":{"description":"Pass back to fetch the next page; empty when no more entries.","type":"string"},"project":{"$ref":"#/components/schemas/Project"},"projects":{"items":{"$ref":"#/components/schemas/Project"},"type":"array"}},"type":"object"},"ListRepoGrantsOutputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/ListRepoGrantsOutputBody.json"],"format":"uri","readOnly":true,"type":"string"},"grants":{"items":{"$ref":"#/components/schemas/RepoGrant"},"type":"array"},"nextPageToken":{"description":"Pass back to fetch the next page; empty when no more entries.","type":"string"}},"required":["grants"],"type":"object"},"ListServiceAccountGrantsOutputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/ListServiceAccountGrantsOutputBody.json"],"format":"uri","readOnly":true,"type":"string"},"grants":{"items":{"$ref":"#/components/schemas/ServiceAccountGrant"},"type":"array"},"nextPageToken":{"description":"Pass back to fetch the next page; empty when no more entries.","type":"string"}},"required":["grants"],"type":"object"},"ListServiceAccountsOutputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/ListServiceAccountsOutputBody.json"],"format":"uri","readOnly":true,"type":"string"},"nextPageToken":{"description":"Pass back to fetch the next page; empty when no more entries.","type":"string"},"serviceAccounts":{"items":{"$ref":"#/components/schemas/ServiceAccountWithGrants"},"type":"array"}},"required":["serviceAccounts"],"type":"object"},"LookupRef":{"additionalProperties":true,"properties":{"id":{"minLength":1,"type":"string"},"type":{"description":"Resource type slug; \"org\", \"project\", \"repo\" are enriched, unknown types pass through.","minLength":1,"type":"string"}},"required":["type","id"],"type":"object"},"LookupRefResult":{"additionalProperties":true,"properties":{"id":{"type":"string"},"name":{"type":"string"},"ownerId":{"type":"string"},"ownerType":{"enum":["org","account"],"type":"string"},"projectId":{"type":"string"},"type":{"type":"string"},"url":{"type":"string"}},"required":["type","id"],"type":"object"},"LookupResourcesOutputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/LookupResourcesOutputBody.json"],"format":"uri","readOnly":true,"type":"string"},"nextPageToken":{"description":"Pass back to fetch the next page; empty when no more entries.","type":"string"},"permission":{"type":"string"},"resourceIds":{"items":{"type":"string"},"type":"array"},"resourceType":{"type":"string"},"resources":{"items":{"$ref":"#/components/schemas/ResourceAccess"},"type":"array"}},"required":["resourceType"],"type":"object"},"MeAuth":{"additionalProperties":true,"properties":{"provider":{"type":"string"},"providerUserId":{"type":"string"}},"required":["provider","providerUserId"],"type":"object"},"MeGlobal":{"additionalProperties":true,"properties":{"accountId":{"type":"string"},"avatarUrl":{"type":"string"},"handle":{"type":"string"},"handles":{"items":{"$ref":"#/components/schemas/MeIdentityHandle"},"type":"array"},"homeJurisdiction":{"type":"string"}},"required":["accountId","handles"],"type":"object"},"MeIdentityHandle":{"additionalProperties":true,"properties":{"email":{"description":"The provider's publicly-visible profile email (from the provider at login; may be empty). NOT the account's contact email.","type":"string"},"handle":{"type":"string"},"provider":{"type":"string"},"providerUserId":{"type":"string"}},"required":["provider","handle","providerUserId"],"type":"object"},"MeRegional":{"additionalProperties":true,"properties":{"bio":{"type":"string"},"company":{"type":"string"},"displayName":{"type":"string"},"email":{"type":"string"},"location":{"type":"string"}},"type":"object"},"MeRegionalUnavailable":{"additionalProperties":true,"properties":{"error":{"description":"Always 'foreign_jurisdiction'. Discriminator for client-side state machines.","enum":["foreign_jurisdiction"],"type":"string"},"homeCoreUrl":{"description":"Deep link into the home console for this account.","type":"string"},"jurisdiction":{"description":"The account's home jurisdiction (e.g. 'us', 'eu').","type":"string"},"message":{"description":"Human-readable copy ready to surface in a UI.","type":"string"}},"required":["error","jurisdiction","homeCoreUrl","message"],"type":"object"},"Membership":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/Membership.json"],"format":"uri","readOnly":true,"type":"string"},"accountId":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"id":{"type":"string"},"orgId":{"type":"string"},"role":{"type":"string"},"status":{"type":"string"},"workosOrgMembershipId":{"type":"string"}},"required":["id","accountId","orgId","role","status","createdAt"],"type":"object"},"Mirror":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/Mirror.json"],"format":"uri","readOnly":true,"type":"string"},"cell":{"description":"Physical cell the mirror's cluster runs in, e.g. aws-us-east-2.","type":"string"},"clusterHost":{"description":"Public host of the cluster serving this mirror.","type":"string"},"createdAt":{"format":"date-time","type":"string"},"installationId":{"format":"int64","type":"integer"},"isArchived":{"type":"boolean"},"isPrivate":{"type":"boolean"},"jurisdiction":{"type":"string"},"mirrorId":{"type":"string"},"owner":{"type":"string"},"provider":{"type":"string"},"repo":{"type":"string"},"status":{"description":"Clone lifecycle: processing (cloning), ready (clonable), failed (initial clone failed), or suspended.","enum":["processing","ready","failed","suspended"],"type":"string"},"suspendedAt":{"format":"date-time","type":"string"}},"required":["mirrorId","provider","owner","repo","clusterHost","createdAt"],"type":"object"},"MirrorCollaborator":{"additionalProperties":true,"properties":{"accountId":{"type":"string"},"handle":{"description":"Primary handle (provider:label), empty if none resolves.","type":"string"},"role":{"description":"reader (pull) or writer (pull+push).","type":"string"}},"required":["accountId","role"],"type":"object"},"OIDCProvider":{"additionalProperties":true,"properties":{"description":{"type":"string"},"displayName":{"type":"string"},"id":{"type":"string"},"issuer":{"type":"string"}},"required":["id","issuer"],"type":"object"},"Org":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/Org.json"],"format":"uri","readOnly":true,"type":"string"},"createdAt":{"format":"date-time","type":"string"},"id":{"type":"string"},"name":{"type":"string"},"region":{"type":"string"},"workosOrganizationId":{"type":"string"}},"required":["id","name","region","createdAt"],"type":"object"},"Project":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/Project.json"],"format":"uri","readOnly":true,"type":"string"},"createdAt":{"format":"date-time","type":"string"},"id":{"type":"string"},"name":{"type":"string"},"ownerId":{"type":"string"},"ownerType":{"enum":["org","account"],"type":"string"},"region":{"type":"string"}},"required":["id","name","ownerType","ownerId","region","createdAt"],"type":"object"},"ProjectGrant":{"additionalProperties":true,"properties":{"granteeId":{"type":"string"},"granteeType":{"type":"string"},"role":{"type":"string"}},"required":["granteeType","granteeId","role"],"type":"object"},"Repo":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/Repo.json"],"format":"uri","readOnly":true,"type":"string"},"clusterHost":{"type":"string"},"foreign":{"type":"boolean"},"id":{"type":"string"},"mirrorSuspended":{"type":"boolean"},"mirrorSuspendedAt":{"type":"string"},"name":{"type":"string"},"objectFormat":{"enum":["sha1","sha256"],"type":"string"},"owningProjectId":{"type":"string"},"path":{"type":"string"},"provisionAttempts":{"format":"int64","type":"integer"},"provisionReason":{"type":"string"},"state":{"enum":["provisioning","active","failed"],"type":"string"},"visibility":{"enum":["public","private"],"type":"string"}},"required":["id","owningProjectId","name"],"type":"object"},"RepoGrant":{"additionalProperties":true,"properties":{"granteeId":{"type":"string"},"granteeType":{"type":"string"},"role":{"type":"string"}},"required":["granteeType","granteeId","role"],"type":"object"},"ResolvedIdentity":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/ResolvedIdentity.json"],"format":"uri","readOnly":true,"type":"string"},"accountId":{"type":"string"},"handle":{"type":"string"},"provider":{"type":"string"},"providerUserId":{"type":"string"}},"required":["accountId","provider","handle","providerUserId"],"type":"object"},"ResourceAccess":{"additionalProperties":true,"properties":{"permissions":{"items":{"type":"string"},"type":"array"},"resourceId":{"type":"string"}},"required":["resourceId","permissions"],"type":"object"},"ServiceAccount":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/ServiceAccount.json"],"format":"uri","readOnly":true,"type":"string"},"accountId":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"name":{"type":"string"},"orgId":{"type":"string"},"status":{"type":"string"},"systemManaged":{"type":"boolean"}},"required":["accountId","name","orgId","status","systemManaged","createdAt"],"type":"object"},"ServiceAccountGrant":{"additionalProperties":true,"properties":{"resourceId":{"type":"string"},"resourceName":{"type":"string"},"resourceType":{"type":"string"},"role":{"type":"string"}},"required":["resourceType","resourceId","role"],"type":"object"},"ServiceAccountWithGrants":{"additionalProperties":true,"properties":{"accountId":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"grants":{"items":{"type":"string"},"type":"array"},"name":{"type":"string"},"orgId":{"type":"string"},"status":{"type":"string"},"systemManaged":{"type":"boolean"}},"required":["grants","accountId","name","orgId","status","systemManaged","createdAt"],"type":"object"},"SetRepoVisibilityInputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/SetRepoVisibilityInputBody.json"],"format":"uri","readOnly":true,"type":"string"},"visibility":{"enum":["public","private"],"type":"string"}},"required":["visibility"],"type":"object"},"SetRepoVisibilityOutputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/SetRepoVisibilityOutputBody.json"],"format":"uri","readOnly":true,"type":"string"},"visibility":{"enum":["public","private"],"type":"string"}},"required":["visibility"],"type":"object"},"UpdateMeInputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/UpdateMeInputBody.json"],"format":"uri","readOnly":true,"type":"string"},"email":{"description":"Contact email.","format":"email","maxLength":254,"minLength":5,"type":"string"}},"required":["email"],"type":"object"},"UpdateMeOutputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/UpdateMeOutputBody.json"],"format":"uri","readOnly":true,"type":"string"},"email":{"type":"string"}},"required":["email"],"type":"object"}},"securitySchemes":{"bearerAuth":{"bearerFormat":"JWT","description":"Bearer token minted by entire-core's device-code flow or STS exchange.","scheme":"bearer","type":"http"},"sessionAuth":{"description":"Console session cookie issued by the browser login flow.","in":"cookie","name":"entire_session","type":"apiKey"}}},"info":{"description":"Entire control plane: identity, orgs, projects, repos, mirrors, service accounts.","title":"Entire Core API","version":"1.0.0"},"openapi":"3.1.0","paths":{"/access/{resourceType}":{"get":{"operationId":"lookupResources","parameters":[{"description":"Maximum entries to return; server may cap further.","explode":false,"in":"query","name":"pageSize","schema":{"description":"Maximum entries to return; server may cap further.","format":"int32","maximum":500,"minimum":0,"type":"integer"}},{"description":"Opaque cursor from a previous response's nextPageToken.","explode":false,"in":"query","name":"pageToken","schema":{"description":"Opaque cursor from a previous response's nextPageToken.","type":"string"}},{"description":"SpiceDB resource type (e.g. \"repo\", \"project\", \"org\").","in":"path","name":"resourceType","required":true,"schema":{"description":"SpiceDB resource type (e.g. \"repo\", \"project\", \"org\").","minLength":1,"type":"string"}},{"description":"Optional: only list resources where the caller has this permission. pageSize/pageToken apply only when set.","explode":false,"in":"query","name":"permission","schema":{"description":"Optional: only list resources where the caller has this permission. pageSize/pageToken apply only when set.","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LookupResourcesOutputBody"}}},"description":"OK"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"List resources of a type the caller can access","tags":["identity"]}},"/access/{resourceType}/{resourceId}":{"get":{"operationId":"getPermissions","parameters":[{"in":"path","name":"resourceType","required":true,"schema":{"minLength":1,"type":"string"}},{"in":"path","name":"resourceId","required":true,"schema":{"minLength":1,"type":"string"}},{"description":"If set, return the SpiceDB trace for this permission instead of the permission list.","explode":false,"in":"query","name":"explain","schema":{"description":"If set, return the SpiceDB trace for this permission instead of the permission list.","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetPermissionsOutputBody"}}},"description":"OK"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"List the caller's permissions on a single resource","tags":["identity"]}},"/audit":{"get":{"operationId":"listAuditEvents","parameters":[{"description":"Maximum entries to return; server may cap further.","explode":false,"in":"query","name":"pageSize","schema":{"description":"Maximum entries to return; server may cap further.","format":"int32","maximum":500,"minimum":0,"type":"integer"}},{"description":"Opaque cursor from a previous response's nextPageToken.","explode":false,"in":"query","name":"pageToken","schema":{"description":"Opaque cursor from a previous response's nextPageToken.","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListAuditEventsOutputBody"}}},"description":"OK"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"List the calling account's recent audit events","tags":["identity"]}},"/clusters":{"get":{"operationId":"listClusters","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListClustersOutputBody"}}},"description":"OK"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"List data-plane clusters attached to this control plane","tags":["clusters"]}},"/identity/handles/{provider}/{handle}":{"get":{"operationId":"resolveHandle","parameters":[{"description":"IdP slug (e.g. \"github\").","in":"path","name":"provider","required":true,"schema":{"description":"IdP slug (e.g. \"github\").","minLength":1,"type":"string"}},{"description":"User-visible handle at the provider.","in":"path","name":"handle","required":true,"schema":{"description":"User-visible handle at the provider.","minLength":1,"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResolvedIdentity"}}},"description":"OK"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Resolve account by external provider handle","tags":["identity"]}},"/lookup":{"post":{"operationId":"batchLookup","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchLookupInputBody"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchLookupOutputBody"}}},"description":"OK"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Batch-resolve (type, id) refs to enriched records","tags":["identity"]}},"/me":{"get":{"operationId":"getMe","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetMeOutputBody"}}},"description":"OK"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Get the calling account's identity and profile","tags":["identity"]},"patch":{"operationId":"updateMe","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMeInputBody"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMeOutputBody"}}},"description":"OK"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Update the calling account's contact email","tags":["identity"]}},"/mirrors":{"delete":{"operationId":"deleteMirror","parameters":[{"explode":false,"in":"query","name":"provider","required":true,"schema":{"enum":["github"],"type":"string"}},{"explode":false,"in":"query","name":"owner","required":true,"schema":{"minLength":1,"type":"string"}},{"explode":false,"in":"query","name":"repo","required":true,"schema":{"minLength":1,"type":"string"}},{"description":"Public host of the cluster serving the mirror.","explode":false,"in":"query","name":"clusterHost","required":true,"schema":{"description":"Public host of the cluster serving the mirror.","minLength":1,"type":"string"}}],"responses":{"204":{"description":"No Content"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"421":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Misdirected Request"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"},"502":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Gateway"},"503":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Service Unavailable"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Delete a mirror by upstream coords + cluster host","tags":["mirrors"]},"get":{"operationId":"listMirrors","parameters":[{"description":"Maximum entries to return; server may cap further.","explode":false,"in":"query","name":"pageSize","schema":{"description":"Maximum entries to return; server may cap further.","format":"int32","maximum":500,"minimum":0,"type":"integer"}},{"description":"Opaque cursor from a previous response's nextPageToken.","explode":false,"in":"query","name":"pageToken","schema":{"description":"Opaque cursor from a previous response's nextPageToken.","type":"string"}},{"description":"Optional: restrict to mirrors on this cluster (public host, e.g. royalcanin.partial.to). Case-sensitive exact match.","explode":false,"in":"query","name":"cluster","schema":{"description":"Optional: restrict to mirrors on this cluster (public host, e.g. royalcanin.partial.to). Case-sensitive exact match.","type":"string"}},{"description":"Optional: restrict to mirrors of this upstream provider, case-insensitive (e.g. \"github\").","explode":false,"in":"query","name":"provider","schema":{"description":"Optional: restrict to mirrors of this upstream provider, case-insensitive (e.g. \"github\").","type":"string"}},{"description":"Optional: restrict to mirrors with this upstream owner login (case-insensitive).","explode":false,"in":"query","name":"owner","schema":{"description":"Optional: restrict to mirrors with this upstream owner login (case-insensitive).","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListMirrorsOutputBody"}}},"description":"OK"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"List mirrors visible to the caller","tags":["mirrors"]},"post":{"operationId":"createMirror","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateMirrorInputBody"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatedMirror"}}},"description":"Created"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Conflict"},"412":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Precondition Failed"},"421":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Misdirected Request"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"},"502":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Gateway"},"503":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Service Unavailable"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Create GitHub mirror","tags":["mirrors"]}},"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/mirrors/available":{"get":{"operationId":"listAvailableMirrors","parameters":[{"description":"Optional: restrict to repos with this owner login (case-insensitive).","explode":false,"in":"query","name":"owner","schema":{"description":"Optional: restrict to repos with this owner login (case-insensitive).","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListAvailableMirrorsOutputBody"}}},"description":"OK"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"},"502":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Gateway"},"503":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Service Unavailable"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"List GitHub repos the caller could onboard as mirrors","tags":["mirrors"]}},"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/mirrors/collaborators":{"delete":{"operationId":"revokeMirrorCollaborator","parameters":[{"explode":false,"in":"query","name":"provider","required":true,"schema":{"enum":["github"],"type":"string"}},{"explode":false,"in":"query","name":"owner","required":true,"schema":{"minLength":1,"type":"string"}},{"explode":false,"in":"query","name":"repo","required":true,"schema":{"minLength":1,"type":"string"}},{"description":"Public host of the cluster serving the mirror.","explode":false,"in":"query","name":"clusterHost","required":true,"schema":{"description":"Public host of the cluster serving the mirror.","minLength":1,"type":"string"}},{"description":"Qualified grantee handle, e.g. github:alice.","explode":false,"in":"query","name":"handle","required":true,"schema":{"description":"Qualified grantee handle, e.g. github:alice.","minLength":1,"type":"string"}}],"responses":{"204":{"description":"No Content"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"421":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Misdirected Request"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"},"502":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Gateway"},"503":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Service Unavailable"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Revoke a user's access to a mirror (live GitHub-admin gated)","tags":["mirrors"]},"get":{"operationId":"listMirrorCollaborators","parameters":[{"explode":false,"in":"query","name":"provider","required":true,"schema":{"enum":["github"],"type":"string"}},{"explode":false,"in":"query","name":"owner","required":true,"schema":{"minLength":1,"type":"string"}},{"explode":false,"in":"query","name":"repo","required":true,"schema":{"minLength":1,"type":"string"}},{"description":"Public host of the cluster serving the mirror.","explode":false,"in":"query","name":"clusterHost","required":true,"schema":{"description":"Public host of the cluster serving the mirror.","minLength":1,"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListMirrorCollaboratorsOutputBody"}}},"description":"OK"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"421":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Misdirected Request"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"},"502":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Gateway"},"503":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Service Unavailable"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"List the principals with access to a mirror (live GitHub-admin gated)","tags":["mirrors"]},"post":{"operationId":"grantMirrorCollaborator","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GrantMirrorCollaboratorInputBody"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GrantedMirrorCollaborator"}}},"description":"OK"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Conflict"},"421":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Misdirected Request"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"},"502":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Gateway"},"503":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Service Unavailable"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Grant a user reader/writer access to a mirror (live GitHub-admin gated)","tags":["mirrors"]}},"/mirrors/{mirrorId}":{"get":{"operationId":"getMirror","parameters":[{"in":"path","name":"mirrorId","required":true,"schema":{"pattern":"^[0-9A-HJKMNP-TV-Z]{26}$","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Mirror"}}},"description":"OK"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Get mirror by id","tags":["mirrors"]}},"/oidc-providers":{"get":{"operationId":"listOIDCProviders","parameters":[{"description":"Maximum entries to return; server may cap further.","explode":false,"in":"query","name":"pageSize","schema":{"description":"Maximum entries to return; server may cap further.","format":"int32","maximum":500,"minimum":0,"type":"integer"}},{"description":"Opaque cursor from a previous response's nextPageToken.","explode":false,"in":"query","name":"pageToken","schema":{"description":"Opaque cursor from a previous response's nextPageToken.","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListOIDCProvidersOutputBody"}}},"description":"OK"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"},"503":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Service Unavailable"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"List federated OIDC identity providers","tags":["identity"]}},"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/orgs":{"get":{"operationId":"listOrgs","parameters":[{"description":"Maximum entries to return; server may cap further.","explode":false,"in":"query","name":"pageSize","schema":{"description":"Maximum entries to return; server may cap further.","format":"int32","maximum":500,"minimum":0,"type":"integer"}},{"description":"Opaque cursor from a previous response's nextPageToken.","explode":false,"in":"query","name":"pageToken","schema":{"description":"Opaque cursor from a previous response's nextPageToken.","type":"string"}},{"description":"Optional: exact-match org name (case-insensitive).","explode":false,"in":"query","name":"name","schema":{"description":"Optional: exact-match org name (case-insensitive).","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListOrgsOutputBody"}}},"description":"OK"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"List organizations the caller can see (or one by name)","tags":["orgs"]},"post":{"operationId":"createOrg","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateOrgInputBody"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Org"}}},"description":"Created"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Conflict"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Create organization","tags":["orgs"]}},"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/orgs/{orgId}":{"delete":{"operationId":"deleteOrg","parameters":[{"in":"path","name":"orgId","required":true,"schema":{"pattern":"^[0-9A-HJKMNP-TV-Z]{26}$","type":"string"}}],"responses":{"204":{"description":"No Content"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Conflict"},"421":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Misdirected Request"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Delete an organization","tags":["orgs"]},"get":{"operationId":"getOrg","parameters":[{"in":"path","name":"orgId","required":true,"schema":{"pattern":"^[0-9A-HJKMNP-TV-Z]{26}$","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Org"}}},"description":"OK"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Get an organization","tags":["orgs"]}},"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/orgs/{orgId}/members":{"get":{"operationId":"listOrgMembers","parameters":[{"description":"Maximum entries to return; server may cap further.","explode":false,"in":"query","name":"pageSize","schema":{"description":"Maximum entries to return; server may cap further.","format":"int32","maximum":500,"minimum":0,"type":"integer"}},{"description":"Opaque cursor from a previous response's nextPageToken.","explode":false,"in":"query","name":"pageToken","schema":{"description":"Opaque cursor from a previous response's nextPageToken.","type":"string"}},{"in":"path","name":"orgId","required":true,"schema":{"pattern":"^[0-9A-HJKMNP-TV-Z]{26}$","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListOrgMembersOutputBody"}}},"description":"OK"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"List members of an organization","tags":["orgs"]},"post":{"operationId":"addOrgMember","parameters":[{"in":"path","name":"orgId","required":true,"schema":{"pattern":"^[0-9A-HJKMNP-TV-Z]{26}$","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddOrgMemberInputBody"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Membership"}}},"description":"Created"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Add a member to an organization","tags":["orgs"]}},"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/orgs/{orgId}/members/{provider}/{providerUserId}":{"delete":{"operationId":"removeOrgMember","parameters":[{"in":"path","name":"orgId","required":true,"schema":{"pattern":"^[0-9A-HJKMNP-TV-Z]{26}$","type":"string"}},{"in":"path","name":"provider","required":true,"schema":{"minLength":1,"type":"string"}},{"in":"path","name":"providerUserId","required":true,"schema":{"minLength":1,"type":"string"}}],"responses":{"204":{"description":"No Content"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Remove a member from an organization","tags":["orgs"]}},"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/orgs/{orgId}/projects":{"get":{"operationId":"listOrgProjects","parameters":[{"description":"Maximum entries to return; server may cap further.","explode":false,"in":"query","name":"pageSize","schema":{"description":"Maximum entries to return; server may cap further.","format":"int32","maximum":500,"minimum":0,"type":"integer"}},{"description":"Opaque cursor from a previous response's nextPageToken.","explode":false,"in":"query","name":"pageToken","schema":{"description":"Opaque cursor from a previous response's nextPageToken.","type":"string"}},{"in":"path","name":"orgId","required":true,"schema":{"pattern":"^[0-9A-HJKMNP-TV-Z]{26}$","type":"string"}},{"description":"Optional: exact-match project name (case-insensitive).","explode":false,"in":"query","name":"name","schema":{"description":"Optional: exact-match project name (case-insensitive).","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListOrgProjectsOutputBody"}}},"description":"OK"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"List projects owned by an organization","tags":["projects"]}},"/projects":{"get":{"operationId":"listProjects","parameters":[{"description":"Maximum entries to return; server may cap further.","explode":false,"in":"query","name":"pageSize","schema":{"description":"Maximum entries to return; server may cap further.","format":"int32","maximum":500,"minimum":0,"type":"integer"}},{"description":"Opaque cursor from a previous response's nextPageToken.","explode":false,"in":"query","name":"pageToken","schema":{"description":"Opaque cursor from a previous response's nextPageToken.","type":"string"}},{"description":"Optional: exact-match project name (case-insensitive).","explode":false,"in":"query","name":"name","schema":{"description":"Optional: exact-match project name (case-insensitive).","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListProjectsOutputBody"}}},"description":"OK"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"List projects accessible to the caller (or one by name)","tags":["projects"]},"post":{"operationId":"createProject","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProjectInputBody"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Project"}}},"description":"Created"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Conflict"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Create project","tags":["projects"]}},"/projects/{projectId}":{"delete":{"operationId":"deleteProject","parameters":[{"in":"path","name":"projectId","required":true,"schema":{"pattern":"^[0-9A-HJKMNP-TV-Z]{26}$","type":"string"}}],"responses":{"204":{"description":"No Content"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Conflict"},"421":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Misdirected Request"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Delete a project","tags":["projects"]},"get":{"operationId":"getProject","parameters":[{"in":"path","name":"projectId","required":true,"schema":{"pattern":"^[0-9A-HJKMNP-TV-Z]{26}$","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Project"}}},"description":"OK"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Get a project by id","tags":["projects"]}},"/projects/{projectId}/grants":{"post":{"operationId":"grantProjectAccess","parameters":[{"in":"path","name":"projectId","required":true,"schema":{"pattern":"^[0-9A-HJKMNP-TV-Z]{26}$","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GrantProjectAccessInputBody"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GrantProjectAccessOutputBody"}}},"description":"Created"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Conflict"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Grant project access to an identity","tags":["projects"]}},"/projects/{projectId}/grants/account/{provider}/{providerUserId}":{"delete":{"operationId":"revokeProjectAccessByProvider","parameters":[{"in":"path","name":"projectId","required":true,"schema":{"pattern":"^[0-9A-HJKMNP-TV-Z]{26}$","type":"string"}},{"in":"path","name":"provider","required":true,"schema":{"minLength":1,"type":"string"}},{"in":"path","name":"providerUserId","required":true,"schema":{"minLength":1,"type":"string"}}],"responses":{"204":{"description":"No Content"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Revoke project access by provider identity","tags":["projects"]}},"/projects/{projectId}/grants/{granteeType}/{granteeId}":{"delete":{"operationId":"revokeProjectAccess","parameters":[{"in":"path","name":"projectId","required":true,"schema":{"pattern":"^[0-9A-HJKMNP-TV-Z]{26}$","type":"string"}},{"in":"path","name":"granteeType","required":true,"schema":{"minLength":1,"type":"string"}},{"in":"path","name":"granteeId","required":true,"schema":{"minLength":1,"type":"string"}}],"responses":{"204":{"description":"No Content"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Revoke project access by grantee id","tags":["projects"]}},"/projects/{projectId}/members":{"get":{"operationId":"listProjectMembers","parameters":[{"description":"Maximum entries to return; server may cap further.","explode":false,"in":"query","name":"pageSize","schema":{"description":"Maximum entries to return; server may cap further.","format":"int32","maximum":500,"minimum":0,"type":"integer"}},{"description":"Opaque cursor from a previous response's nextPageToken.","explode":false,"in":"query","name":"pageToken","schema":{"description":"Opaque cursor from a previous response's nextPageToken.","type":"string"}},{"in":"path","name":"projectId","required":true,"schema":{"pattern":"^[0-9A-HJKMNP-TV-Z]{26}$","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListProjectMembersOutputBody"}}},"description":"OK"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"List project members and their roles","tags":["projects"]}},"/projects/{projectId}/repos":{"get":{"operationId":"listProjectRepos","parameters":[{"description":"Maximum entries to return; server may cap further.","explode":false,"in":"query","name":"pageSize","schema":{"description":"Maximum entries to return; server may cap further.","format":"int32","maximum":500,"minimum":0,"type":"integer"}},{"description":"Opaque cursor from a previous response's nextPageToken.","explode":false,"in":"query","name":"pageToken","schema":{"description":"Opaque cursor from a previous response's nextPageToken.","type":"string"}},{"in":"path","name":"projectId","required":true,"schema":{"pattern":"^[0-9A-HJKMNP-TV-Z]{26}$","type":"string"}},{"description":"Optional: exact-match repo name (case-insensitive).","explode":false,"in":"query","name":"name","schema":{"description":"Optional: exact-match repo name (case-insensitive).","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListProjectReposOutputBody"}}},"description":"OK"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"List repositories in a project (or one by name)","tags":["repos"]}},"/repos":{"post":{"operationId":"createRepo","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateRepoInputBody"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Repo"}}},"description":"Created"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Conflict"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"},"503":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Service Unavailable"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Create repository","tags":["repos"]}},"/repos/{repoId}":{"delete":{"operationId":"deleteRepo","parameters":[{"in":"path","name":"repoId","required":true,"schema":{"pattern":"^[0-9A-HJKMNP-TV-Z]{26}$","type":"string"}}],"responses":{"204":{"description":"No Content"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"421":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Misdirected Request"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"},"502":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Gateway"},"503":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Service Unavailable"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Delete repository","tags":["repos"]},"get":{"operationId":"getRepo","parameters":[{"in":"path","name":"repoId","required":true,"schema":{"pattern":"^[0-9A-HJKMNP-TV-Z]{26}$","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Repo"}}},"description":"OK"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Get repository","tags":["repos"]}},"/repos/{repoId}/grants":{"get":{"operationId":"listRepoGrants","parameters":[{"description":"Maximum entries to return; server may cap further.","explode":false,"in":"query","name":"pageSize","schema":{"description":"Maximum entries to return; server may cap further.","format":"int32","maximum":500,"minimum":0,"type":"integer"}},{"description":"Opaque cursor from a previous response's nextPageToken.","explode":false,"in":"query","name":"pageToken","schema":{"description":"Opaque cursor from a previous response's nextPageToken.","type":"string"}},{"in":"path","name":"repoId","required":true,"schema":{"pattern":"^[0-9A-HJKMNP-TV-Z]{26}$","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListRepoGrantsOutputBody"}}},"description":"OK"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"List repo grants","tags":["repos"]},"post":{"operationId":"grantRepoAccess","parameters":[{"in":"path","name":"repoId","required":true,"schema":{"pattern":"^[0-9A-HJKMNP-TV-Z]{26}$","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GrantRepoAccessInputBody"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GrantRepoAccessOutputBody"}}},"description":"Created"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Conflict"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Grant repo access to an identity","tags":["repos"]}},"/repos/{repoId}/grants/account/{provider}/{providerUserId}":{"delete":{"operationId":"revokeRepoAccessByProvider","parameters":[{"in":"path","name":"repoId","required":true,"schema":{"pattern":"^[0-9A-HJKMNP-TV-Z]{26}$","type":"string"}},{"in":"path","name":"provider","required":true,"schema":{"minLength":1,"type":"string"}},{"in":"path","name":"providerUserId","required":true,"schema":{"minLength":1,"type":"string"}}],"responses":{"204":{"description":"No Content"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Revoke repo access by provider identity","tags":["repos"]}},"/repos/{repoId}/grants/{granteeType}/{granteeId}":{"delete":{"operationId":"revokeRepoAccess","parameters":[{"in":"path","name":"repoId","required":true,"schema":{"pattern":"^[0-9A-HJKMNP-TV-Z]{26}$","type":"string"}},{"in":"path","name":"granteeType","required":true,"schema":{"minLength":1,"type":"string"}},{"in":"path","name":"granteeId","required":true,"schema":{"minLength":1,"type":"string"}}],"responses":{"204":{"description":"No Content"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Revoke repo access by grantee id","tags":["repos"]}},"/repos/{repoId}/visibility":{"get":{"operationId":"getRepoVisibility","parameters":[{"in":"path","name":"repoId","required":true,"schema":{"pattern":"^[0-9A-HJKMNP-TV-Z]{26}$","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetRepoVisibilityOutputBody"}}},"description":"OK"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Get repository visibility","tags":["repos"]},"put":{"operationId":"setRepoVisibility","parameters":[{"in":"path","name":"repoId","required":true,"schema":{"pattern":"^[0-9A-HJKMNP-TV-Z]{26}$","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetRepoVisibilityInputBody"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetRepoVisibilityOutputBody"}}},"description":"OK"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Set repository visibility","tags":["repos"]}},"/service-accounts":{"get":{"operationId":"listServiceAccounts","parameters":[{"description":"Maximum entries to return; server may cap further.","explode":false,"in":"query","name":"pageSize","schema":{"description":"Maximum entries to return; server may cap further.","format":"int32","maximum":500,"minimum":0,"type":"integer"}},{"description":"Opaque cursor from a previous response's nextPageToken.","explode":false,"in":"query","name":"pageToken","schema":{"description":"Opaque cursor from a previous response's nextPageToken.","type":"string"}},{"explode":false,"in":"query","name":"orgId","required":true,"schema":{"pattern":"^[0-9A-HJKMNP-TV-Z]{26}$","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListServiceAccountsOutputBody"}}},"description":"OK"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"},"503":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Service Unavailable"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"List service accounts in an org","tags":["service-accounts"]},"post":{"operationId":"createServiceAccount","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateServiceAccountInputBody"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceAccount"}}},"description":"Created"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Conflict"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"},"503":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Service Unavailable"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Create service account","tags":["service-accounts"]}},"/service-accounts/{accountId}":{"delete":{"operationId":"deleteServiceAccount","parameters":[{"in":"path","name":"accountId","required":true,"schema":{"minLength":1,"type":"string"}}],"responses":{"204":{"description":"No Content"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"},"503":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Service Unavailable"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Delete service account","tags":["service-accounts"]},"get":{"operationId":"getServiceAccount","parameters":[{"in":"path","name":"accountId","required":true,"schema":{"minLength":1,"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceAccount"}}},"description":"OK"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"},"503":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Service Unavailable"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Get service account","tags":["service-accounts"]}},"/service-accounts/{accountId}/bindings":{"get":{"operationId":"listBindings","parameters":[{"description":"Maximum entries to return; server may cap further.","explode":false,"in":"query","name":"pageSize","schema":{"description":"Maximum entries to return; server may cap further.","format":"int32","maximum":500,"minimum":0,"type":"integer"}},{"description":"Opaque cursor from a previous response's nextPageToken.","explode":false,"in":"query","name":"pageToken","schema":{"description":"Opaque cursor from a previous response's nextPageToken.","type":"string"}},{"in":"path","name":"accountId","required":true,"schema":{"minLength":1,"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListBindingsOutputBody"}}},"description":"OK"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"},"503":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Service Unavailable"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"List OIDC bindings","tags":["service-accounts"]},"post":{"operationId":"createBinding","parameters":[{"in":"path","name":"accountId","required":true,"schema":{"minLength":1,"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateBindingInputBody"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Binding"}}},"description":"Created"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Conflict"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"},"503":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Service Unavailable"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Create OIDC binding","tags":["service-accounts"]}},"/service-accounts/{accountId}/bindings/{bindingId}":{"delete":{"operationId":"deleteBinding","parameters":[{"in":"path","name":"accountId","required":true,"schema":{"minLength":1,"type":"string"}},{"in":"path","name":"bindingId","required":true,"schema":{"minLength":1,"type":"string"}}],"responses":{"204":{"description":"No Content"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"},"503":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Service Unavailable"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Delete OIDC binding","tags":["service-accounts"]}},"/service-accounts/{accountId}/grants":{"get":{"operationId":"listServiceAccountGrants","parameters":[{"description":"Maximum entries to return; server may cap further.","explode":false,"in":"query","name":"pageSize","schema":{"description":"Maximum entries to return; server may cap further.","format":"int32","maximum":500,"minimum":0,"type":"integer"}},{"description":"Opaque cursor from a previous response's nextPageToken.","explode":false,"in":"query","name":"pageToken","schema":{"description":"Opaque cursor from a previous response's nextPageToken.","type":"string"}},{"in":"path","name":"accountId","required":true,"schema":{"minLength":1,"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListServiceAccountGrantsOutputBody"}}},"description":"OK"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"},"503":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Service Unavailable"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"List service account grants","tags":["service-accounts"]},"post":{"operationId":"grantServiceAccountAccess","parameters":[{"in":"path","name":"accountId","required":true,"schema":{"minLength":1,"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GrantServiceAccountAccessInputBody"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GrantServiceAccountAccessOutputBody"}}},"description":"Created"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Conflict"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"},"503":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Service Unavailable"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Grant service account access on a repo or project","tags":["service-accounts"]}},"/service-accounts/{accountId}/grants/{resourceType}/{resourceId}":{"delete":{"operationId":"revokeServiceAccountAccess","parameters":[{"in":"path","name":"accountId","required":true,"schema":{"minLength":1,"type":"string"}},{"in":"path","name":"resourceType","required":true,"schema":{"enum":["repo","project"],"type":"string"}},{"in":"path","name":"resourceId","required":true,"schema":{"minLength":1,"type":"string"}}],"responses":{"204":{"description":"No Content"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"},"503":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Service Unavailable"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Revoke service account access","tags":["service-accounts"]}},"/version":{"get":{"operationId":"getVersion","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetVersionOutputBody"}}},"description":"OK"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"summary":"Get the server version and mode","tags":["meta"]}}},"servers":[{"url":"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/api/v1"}]} \ No newline at end of file +{"components":{"schemas":{"AddOrgMemberInputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/AddOrgMemberInputBody.json"],"format":"uri","readOnly":true,"type":"string"},"provider":{"minLength":1,"type":"string"},"providerUserId":{"minLength":1,"type":"string"},"role":{"default":"member","description":"Role at the org; defaults to member.","enum":["owner","admin","member"],"type":"string"}},"required":["provider","providerUserId"],"type":"object"},"AuditEvent":{"additionalProperties":true,"properties":{"actorId":{"type":"string"},"eventType":{"type":"string"},"id":{"type":"string"},"ipAddress":{"description":"Source IP recorded when the event was logged.","type":"string"},"metadata":{"additionalProperties":{},"type":"object"},"occurredAt":{"format":"date-time","type":"string"}},"required":["id","occurredAt","eventType","actorId"],"type":"object"},"AvailableMirror":{"additionalProperties":true,"properties":{"access":{"description":"Caller's effective GitHub access: read, write, or admin.","enum":["read","write","admin"],"type":"string"},"isArchived":{"type":"boolean"},"isPrivate":{"type":"boolean"},"owner":{"type":"string"},"repo":{"type":"string"},"status":{"description":"available (can onboard), mirrored (already mirrored), or owner-only (personal repo of another user).","enum":["available","mirrored","owner-only"],"type":"string"}},"required":["owner","repo","access","status"],"type":"object"},"BatchLookupInputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/BatchLookupInputBody.json"],"format":"uri","readOnly":true,"type":"string"},"refs":{"items":{"$ref":"#/components/schemas/LookupRef"},"maxItems":100,"minItems":1,"type":"array"}},"required":["refs"],"type":"object"},"BatchLookupOutputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/BatchLookupOutputBody.json"],"format":"uri","readOnly":true,"type":"string"},"refs":{"items":{"$ref":"#/components/schemas/LookupRefResult"},"type":"array"}},"required":["refs"],"type":"object"},"Binding":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/Binding.json"],"format":"uri","readOnly":true,"type":"string"},"accountId":{"type":"string"},"attributeFilter":{},"createdAt":{"format":"date-time","type":"string"},"id":{"type":"string"},"providerId":{"type":"string"}},"required":["id","accountId","providerId","attributeFilter","createdAt"],"type":"object"},"Cluster":{"additionalProperties":true,"properties":{"apiUrl":{"type":"string"},"isDefault":{"type":"boolean"},"jurisdiction":{"type":"string"},"publicUrl":{"type":"string"},"slug":{"type":"string"}},"required":["slug","jurisdiction","publicUrl","isDefault"],"type":"object"},"CreateBindingInputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/CreateBindingInputBody.json"],"format":"uri","readOnly":true,"type":"string"},"attributeFilter":{"description":"Exact-match key/value map; empty filter matches any token."},"providerId":{"minLength":1,"type":"string"}},"required":["providerId"],"type":"object"},"CreateMirrorInputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/CreateMirrorInputBody.json"],"format":"uri","readOnly":true,"type":"string"},"clusterHost":{"description":"DNS host of the destination cluster.","minLength":1,"type":"string"},"owner":{"minLength":1,"type":"string"},"provider":{"enum":["github"],"type":"string"},"repo":{"minLength":1,"type":"string"}},"required":["provider","owner","repo","clusterHost"],"type":"object"},"CreateOrgInputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/CreateOrgInputBody.json"],"format":"uri","readOnly":true,"type":"string"},"name":{"description":"Display name.","maxLength":100,"minLength":1,"type":"string"},"region":{"description":"Jurisdiction slug; defaults to the server's home jurisdiction.","type":"string"}},"required":["name"],"type":"object"},"CreateProjectInputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/CreateProjectInputBody.json"],"format":"uri","readOnly":true,"type":"string"},"name":{"maxLength":100,"minLength":1,"type":"string"},"ownerId":{"minLength":1,"type":"string"},"ownerType":{"enum":["org","account"],"type":"string"},"region":{"type":"string"}},"required":["name","ownerType","ownerId"],"type":"object"},"CreateRepoInputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/CreateRepoInputBody.json"],"format":"uri","readOnly":true,"type":"string"},"clusterHost":{"description":"Public host of the cluster to pin the repo to (e.g. royalcanin.partial.to); empty lands on the jurisdiction default.","type":"string"},"name":{"minLength":1,"type":"string"},"objectFormat":{"description":"Hash format; defaults to sha1.","enum":["sha1","sha256"],"type":"string"},"projectId":{"pattern":"^[0-9A-HJKMNP-TV-Z]{26}$","type":"string"}},"required":["projectId","name"],"type":"object"},"CreateServiceAccountInputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/CreateServiceAccountInputBody.json"],"format":"uri","readOnly":true,"type":"string"},"name":{"minLength":1,"type":"string"},"orgId":{"pattern":"^[0-9A-HJKMNP-TV-Z]{26}$","type":"string"}},"required":["orgId","name"],"type":"object"},"CreatedMirror":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/CreatedMirror.json"],"format":"uri","readOnly":true,"type":"string"},"created":{"description":"true on fresh creation; false when an existing mirror was returned.","type":"boolean"},"empty":{"description":"true when the upstream has no refs to clone.","type":"boolean"},"mirrorId":{"type":"string"},"mirrorUrl":{"type":"string"},"publicUrl":{"type":"string"}},"required":["mirrorId","mirrorUrl","publicUrl","created","empty"],"type":"object"},"ErrorDetail":{"additionalProperties":true,"properties":{"location":{"description":"Where the error occurred, e.g. 'body.items[3].tags' or 'path.thing-id'","type":"string"},"message":{"description":"Error message text","type":"string"},"value":{"description":"The value at the given location"}},"type":"object"},"ErrorModel":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/ErrorModel.json"],"format":"uri","readOnly":true,"type":"string"},"detail":{"description":"A human-readable explanation specific to this occurrence of the problem.","examples":["Property foo is required but is missing."],"type":"string"},"errors":{"description":"Optional list of individual error details","items":{"$ref":"#/components/schemas/ErrorDetail"},"type":"array"},"instance":{"description":"A URI reference that identifies the specific occurrence of the problem.","examples":["https://example.com/error-log/abc123"],"format":"uri","type":"string"},"status":{"description":"HTTP status code","examples":[400],"format":"int64","type":"integer"},"title":{"description":"A short, human-readable summary of the problem type. This value should not change between occurrences of the error.","examples":["Bad Request"],"type":"string"},"type":{"default":"about:blank","description":"A URI reference to human-readable documentation for the error.","examples":["https://example.com/errors/example"],"format":"uri","type":"string"}},"type":"object"},"GetMeOutputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/GetMeOutputBody.json"],"format":"uri","readOnly":true,"type":"string"},"auth":{"$ref":"#/components/schemas/MeAuth"},"global":{"$ref":"#/components/schemas/MeGlobal"},"jurisdiction":{"type":"string"},"mode":{"enum":["standalone","global","regional"],"type":"string"},"regional":{"$ref":"#/components/schemas/MeRegional"},"regionalUnavailable":{"$ref":"#/components/schemas/MeRegionalUnavailable"}},"required":["global","auth"],"type":"object"},"GetPermissionsOutputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/GetPermissionsOutputBody.json"],"format":"uri","readOnly":true,"type":"string"},"explain":{"additionalProperties":{},"type":"object"},"permissions":{"items":{"type":"string"},"type":"array"},"resourceId":{"type":"string"},"resourceType":{"type":"string"}},"required":["resourceType","resourceId"],"type":"object"},"GetRepoVisibilityOutputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/GetRepoVisibilityOutputBody.json"],"format":"uri","readOnly":true,"type":"string"},"visibility":{"enum":["public","private"],"type":"string"}},"required":["visibility"],"type":"object"},"GetVersionOutputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/GetVersionOutputBody.json"],"format":"uri","readOnly":true,"type":"string"},"mode":{"description":"Server mode.","enum":["standalone","global","regional"],"type":"string"},"version":{"description":"Git commit SHA of the running entire-core binary, or \"dev\" for an untagged local build.","type":"string"}},"required":["version"],"type":"object"},"GrantMirrorCollaboratorInputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/GrantMirrorCollaboratorInputBody.json"],"format":"uri","readOnly":true,"type":"string"},"clusterHost":{"description":"Public host of the cluster serving the mirror.","minLength":1,"type":"string"},"handle":{"description":"Qualified grantee handle, e.g. github:alice.","minLength":1,"type":"string"},"owner":{"minLength":1,"type":"string"},"provider":{"enum":["github"],"type":"string"},"repo":{"minLength":1,"type":"string"},"role":{"description":"Grant level: reader (pull) or writer (pull+push).","enum":["reader","writer"],"type":"string"}},"required":["provider","owner","repo","clusterHost","handle","role"],"type":"object"},"GrantProjectAccessInputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/GrantProjectAccessInputBody.json"],"format":"uri","readOnly":true,"type":"string"},"granteeType":{"default":"account","enum":["account"],"type":"string"},"provider":{"minLength":1,"type":"string"},"providerUserId":{"minLength":1,"type":"string"},"role":{"enum":["reader","writer","admin"],"type":"string"}},"required":["provider","providerUserId","role"],"type":"object"},"GrantProjectAccessOutputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/GrantProjectAccessOutputBody.json"],"format":"uri","readOnly":true,"type":"string"},"status":{"type":"string"}},"required":["status"],"type":"object"},"GrantRepoAccessInputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/GrantRepoAccessInputBody.json"],"format":"uri","readOnly":true,"type":"string"},"granteeType":{"default":"account","enum":["account"],"type":"string"},"provider":{"minLength":1,"type":"string"},"providerUserId":{"minLength":1,"type":"string"},"role":{"enum":["reader","writer","admin"],"type":"string"}},"required":["provider","providerUserId","role"],"type":"object"},"GrantRepoAccessOutputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/GrantRepoAccessOutputBody.json"],"format":"uri","readOnly":true,"type":"string"},"status":{"type":"string"}},"required":["status"],"type":"object"},"GrantServiceAccountAccessInputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/GrantServiceAccountAccessInputBody.json"],"format":"uri","readOnly":true,"type":"string"},"resourceId":{"minLength":1,"type":"string"},"resourceType":{"enum":["repo","project"],"type":"string"},"role":{"enum":["reader","writer","admin"],"type":"string"}},"required":["resourceType","resourceId","role"],"type":"object"},"GrantServiceAccountAccessOutputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/GrantServiceAccountAccessOutputBody.json"],"format":"uri","readOnly":true,"type":"string"},"status":{"type":"string"}},"required":["status"],"type":"object"},"GrantedMirrorCollaborator":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/GrantedMirrorCollaborator.json"],"format":"uri","readOnly":true,"type":"string"},"accountId":{"description":"Entire account the grant was written for.","type":"string"},"role":{"type":"string"}},"required":["accountId","role"],"type":"object"},"ListAuditEventsOutputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/ListAuditEventsOutputBody.json"],"format":"uri","readOnly":true,"type":"string"},"events":{"items":{"$ref":"#/components/schemas/AuditEvent"},"type":"array"},"nextPageToken":{"description":"Pass back to fetch the next page; empty when no more entries.","type":"string"}},"required":["events"],"type":"object"},"ListAvailableMirrorsOutputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/ListAvailableMirrorsOutputBody.json"],"format":"uri","readOnly":true,"type":"string"},"available":{"items":{"$ref":"#/components/schemas/AvailableMirror"},"type":"array"}},"required":["available"],"type":"object"},"ListBindingsOutputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/ListBindingsOutputBody.json"],"format":"uri","readOnly":true,"type":"string"},"bindings":{"items":{"$ref":"#/components/schemas/Binding"},"type":"array"},"nextPageToken":{"description":"Pass back to fetch the next page; empty when no more entries.","type":"string"}},"required":["bindings"],"type":"object"},"ListClustersOutputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/ListClustersOutputBody.json"],"format":"uri","readOnly":true,"type":"string"},"clusters":{"items":{"$ref":"#/components/schemas/Cluster"},"type":"array"}},"required":["clusters"],"type":"object"},"ListMirrorCollaboratorsOutputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/ListMirrorCollaboratorsOutputBody.json"],"format":"uri","readOnly":true,"type":"string"},"collaborators":{"items":{"$ref":"#/components/schemas/MirrorCollaborator"},"type":"array"}},"required":["collaborators"],"type":"object"},"ListMirrorsOutputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/ListMirrorsOutputBody.json"],"format":"uri","readOnly":true,"type":"string"},"mirrors":{"items":{"$ref":"#/components/schemas/Mirror"},"type":"array"},"nextPageToken":{"description":"Pass back to fetch the next page; empty when no more entries.","type":"string"}},"required":["mirrors"],"type":"object"},"ListOIDCProvidersOutputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/ListOIDCProvidersOutputBody.json"],"format":"uri","readOnly":true,"type":"string"},"nextPageToken":{"description":"Pass back to fetch the next page; empty when no more entries.","type":"string"},"providers":{"items":{"$ref":"#/components/schemas/OIDCProvider"},"type":"array"}},"required":["providers"],"type":"object"},"ListOrgMembersOutputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/ListOrgMembersOutputBody.json"],"format":"uri","readOnly":true,"type":"string"},"members":{"items":{"$ref":"#/components/schemas/Membership"},"type":"array"},"nextPageToken":{"description":"Pass back to fetch the next page; empty when no more entries.","type":"string"}},"required":["members"],"type":"object"},"ListOrgProjectsOutputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/ListOrgProjectsOutputBody.json"],"format":"uri","readOnly":true,"type":"string"},"nextPageToken":{"description":"Pass back to fetch the next page; empty when no more entries.","type":"string"},"project":{"$ref":"#/components/schemas/Project"},"projects":{"items":{"$ref":"#/components/schemas/Project"},"type":"array"}},"type":"object"},"ListOrgsOutputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/ListOrgsOutputBody.json"],"format":"uri","readOnly":true,"type":"string"},"nextPageToken":{"description":"Pass back to fetch the next page; empty when no more entries.","type":"string"},"org":{"$ref":"#/components/schemas/Org"},"orgs":{"items":{"$ref":"#/components/schemas/Org"},"type":"array"}},"type":"object"},"ListProjectMembersOutputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/ListProjectMembersOutputBody.json"],"format":"uri","readOnly":true,"type":"string"},"members":{"items":{"$ref":"#/components/schemas/ProjectGrant"},"type":"array"},"nextPageToken":{"description":"Pass back to fetch the next page; empty when no more entries.","type":"string"}},"required":["members"],"type":"object"},"ListProjectReposOutputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/ListProjectReposOutputBody.json"],"format":"uri","readOnly":true,"type":"string"},"nextPageToken":{"description":"Pass back to fetch the next page; empty when no more entries.","type":"string"},"repo":{"$ref":"#/components/schemas/Repo"},"repos":{"items":{"$ref":"#/components/schemas/Repo"},"type":"array"}},"type":"object"},"ListProjectsOutputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/ListProjectsOutputBody.json"],"format":"uri","readOnly":true,"type":"string"},"nextPageToken":{"description":"Pass back to fetch the next page; empty when no more entries.","type":"string"},"project":{"$ref":"#/components/schemas/Project"},"projects":{"items":{"$ref":"#/components/schemas/Project"},"type":"array"}},"type":"object"},"ListRepoGrantsOutputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/ListRepoGrantsOutputBody.json"],"format":"uri","readOnly":true,"type":"string"},"grants":{"items":{"$ref":"#/components/schemas/RepoGrant"},"type":"array"},"nextPageToken":{"description":"Pass back to fetch the next page; empty when no more entries.","type":"string"}},"required":["grants"],"type":"object"},"ListServiceAccountGrantsOutputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/ListServiceAccountGrantsOutputBody.json"],"format":"uri","readOnly":true,"type":"string"},"grants":{"items":{"$ref":"#/components/schemas/ServiceAccountGrant"},"type":"array"},"nextPageToken":{"description":"Pass back to fetch the next page; empty when no more entries.","type":"string"}},"required":["grants"],"type":"object"},"ListServiceAccountsOutputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/ListServiceAccountsOutputBody.json"],"format":"uri","readOnly":true,"type":"string"},"nextPageToken":{"description":"Pass back to fetch the next page; empty when no more entries.","type":"string"},"serviceAccounts":{"items":{"$ref":"#/components/schemas/ServiceAccountWithGrants"},"type":"array"}},"required":["serviceAccounts"],"type":"object"},"LookupRef":{"additionalProperties":true,"properties":{"id":{"minLength":1,"type":"string"},"type":{"description":"Resource type slug; \"org\", \"project\", \"repo\" are enriched, unknown types pass through.","minLength":1,"type":"string"}},"required":["type","id"],"type":"object"},"LookupRefResult":{"additionalProperties":true,"properties":{"id":{"type":"string"},"name":{"type":"string"},"ownerId":{"type":"string"},"ownerType":{"enum":["org","account"],"type":"string"},"projectId":{"type":"string"},"type":{"type":"string"},"url":{"type":"string"}},"required":["type","id"],"type":"object"},"LookupResourcesOutputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/LookupResourcesOutputBody.json"],"format":"uri","readOnly":true,"type":"string"},"nextPageToken":{"description":"Pass back to fetch the next page; empty when no more entries.","type":"string"},"permission":{"type":"string"},"resourceIds":{"items":{"type":"string"},"type":"array"},"resourceType":{"type":"string"},"resources":{"items":{"$ref":"#/components/schemas/ResourceAccess"},"type":"array"}},"required":["resourceType"],"type":"object"},"MeAuth":{"additionalProperties":true,"properties":{"provider":{"type":"string"},"providerUserId":{"type":"string"}},"required":["provider","providerUserId"],"type":"object"},"MeGlobal":{"additionalProperties":true,"properties":{"accountId":{"type":"string"},"avatarUrl":{"type":"string"},"handle":{"type":"string"},"handles":{"items":{"$ref":"#/components/schemas/MeIdentityHandle"},"type":"array"},"homeJurisdiction":{"type":"string"}},"required":["accountId","handles"],"type":"object"},"MeIdentityHandle":{"additionalProperties":true,"properties":{"email":{"description":"The provider's publicly-visible profile email (from the provider at login; may be empty). NOT the account's contact email.","type":"string"},"handle":{"type":"string"},"provider":{"type":"string"},"providerUserId":{"type":"string"}},"required":["provider","handle","providerUserId"],"type":"object"},"MeRegional":{"additionalProperties":true,"properties":{"bio":{"type":"string"},"company":{"type":"string"},"displayName":{"type":"string"},"email":{"type":"string"},"location":{"type":"string"}},"type":"object"},"MeRegionalUnavailable":{"additionalProperties":true,"properties":{"error":{"description":"Always 'foreign_jurisdiction'. Discriminator for client-side state machines.","enum":["foreign_jurisdiction"],"type":"string"},"homeCoreUrl":{"description":"Deep link into the home console for this account.","type":"string"},"jurisdiction":{"description":"The account's home jurisdiction (e.g. 'us', 'eu').","type":"string"},"message":{"description":"Human-readable copy ready to surface in a UI.","type":"string"}},"required":["error","jurisdiction","homeCoreUrl","message"],"type":"object"},"Membership":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/Membership.json"],"format":"uri","readOnly":true,"type":"string"},"accountId":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"id":{"type":"string"},"orgId":{"type":"string"},"role":{"type":"string"},"status":{"type":"string"},"workosOrgMembershipId":{"type":"string"}},"required":["id","accountId","orgId","role","status","createdAt"],"type":"object"},"Mirror":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/Mirror.json"],"format":"uri","readOnly":true,"type":"string"},"cell":{"description":"Physical cell the mirror's cluster runs in, e.g. aws-us-east-2.","type":"string"},"clusterHost":{"description":"Public host of the cluster serving this mirror.","type":"string"},"createdAt":{"format":"date-time","type":"string"},"installationId":{"format":"int64","type":"integer"},"isArchived":{"type":"boolean"},"isPrivate":{"type":"boolean"},"jurisdiction":{"type":"string"},"mirrorId":{"type":"string"},"owner":{"type":"string"},"provider":{"type":"string"},"repo":{"type":"string"},"status":{"description":"Clone lifecycle: processing (cloning), ready (clonable), failed (initial clone failed), or suspended.","enum":["processing","ready","failed","suspended"],"type":"string"},"suspendedAt":{"format":"date-time","type":"string"}},"required":["mirrorId","provider","owner","repo","clusterHost","createdAt"],"type":"object"},"MirrorCollaborator":{"additionalProperties":true,"properties":{"accountId":{"type":"string"},"handle":{"description":"Primary handle (provider:label), empty if none resolves.","type":"string"},"role":{"description":"reader (pull) or writer (pull+push).","type":"string"}},"required":["accountId","role"],"type":"object"},"OIDCProvider":{"additionalProperties":true,"properties":{"description":{"type":"string"},"displayName":{"type":"string"},"id":{"type":"string"},"issuer":{"type":"string"}},"required":["id","issuer"],"type":"object"},"Org":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/Org.json"],"format":"uri","readOnly":true,"type":"string"},"createdAt":{"format":"date-time","type":"string"},"id":{"type":"string"},"name":{"type":"string"},"region":{"type":"string"},"workosOrganizationId":{"type":"string"}},"required":["id","name","region","createdAt"],"type":"object"},"Project":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/Project.json"],"format":"uri","readOnly":true,"type":"string"},"createdAt":{"format":"date-time","type":"string"},"id":{"type":"string"},"name":{"type":"string"},"ownerId":{"type":"string"},"ownerType":{"enum":["org","account"],"type":"string"},"region":{"type":"string"}},"required":["id","name","ownerType","ownerId","region","createdAt"],"type":"object"},"ProjectGrant":{"additionalProperties":true,"properties":{"granteeId":{"type":"string"},"granteeName":{"type":"string"},"granteeType":{"type":"string"},"role":{"type":"string"},"source":{"type":"string"}},"required":["granteeType","granteeId","role","source"],"type":"object"},"Repo":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/Repo.json"],"format":"uri","readOnly":true,"type":"string"},"clusterHost":{"type":"string"},"foreign":{"type":"boolean"},"id":{"type":"string"},"mirrorSuspended":{"type":"boolean"},"mirrorSuspendedAt":{"type":"string"},"name":{"type":"string"},"objectFormat":{"enum":["sha1","sha256"],"type":"string"},"owningProjectId":{"type":"string"},"path":{"type":"string"},"provisionAttempts":{"format":"int64","type":"integer"},"provisionReason":{"type":"string"},"state":{"enum":["provisioning","active","failed"],"type":"string"},"visibility":{"enum":["public","private"],"type":"string"}},"required":["id","owningProjectId","name"],"type":"object"},"RepoGrant":{"additionalProperties":true,"properties":{"granteeId":{"type":"string"},"granteeName":{"type":"string"},"granteeType":{"type":"string"},"role":{"type":"string"},"source":{"type":"string"}},"required":["granteeType","granteeId","role","source"],"type":"object"},"ResolvedIdentity":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/ResolvedIdentity.json"],"format":"uri","readOnly":true,"type":"string"},"accountId":{"type":"string"},"handle":{"type":"string"},"provider":{"type":"string"},"providerUserId":{"type":"string"}},"required":["accountId","provider","handle","providerUserId"],"type":"object"},"ResourceAccess":{"additionalProperties":true,"properties":{"permissions":{"items":{"type":"string"},"type":"array"},"resourceId":{"type":"string"}},"required":["resourceId","permissions"],"type":"object"},"ServiceAccount":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/ServiceAccount.json"],"format":"uri","readOnly":true,"type":"string"},"accountId":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"name":{"type":"string"},"orgId":{"type":"string"},"status":{"type":"string"},"systemManaged":{"type":"boolean"}},"required":["accountId","name","orgId","status","systemManaged","createdAt"],"type":"object"},"ServiceAccountGrant":{"additionalProperties":true,"properties":{"resourceId":{"type":"string"},"resourceName":{"type":"string"},"resourceType":{"type":"string"},"role":{"type":"string"}},"required":["resourceType","resourceId","role"],"type":"object"},"ServiceAccountWithGrants":{"additionalProperties":true,"properties":{"accountId":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"grants":{"items":{"type":"string"},"type":"array"},"name":{"type":"string"},"orgId":{"type":"string"},"status":{"type":"string"},"systemManaged":{"type":"boolean"}},"required":["grants","accountId","name","orgId","status","systemManaged","createdAt"],"type":"object"},"SetRepoVisibilityInputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/SetRepoVisibilityInputBody.json"],"format":"uri","readOnly":true,"type":"string"},"visibility":{"enum":["public","private"],"type":"string"}},"required":["visibility"],"type":"object"},"SetRepoVisibilityOutputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/SetRepoVisibilityOutputBody.json"],"format":"uri","readOnly":true,"type":"string"},"visibility":{"enum":["public","private"],"type":"string"}},"required":["visibility"],"type":"object"},"UpdateMeInputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/UpdateMeInputBody.json"],"format":"uri","readOnly":true,"type":"string"},"email":{"description":"Contact email.","format":"email","maxLength":254,"minLength":5,"type":"string"}},"required":["email"],"type":"object"},"UpdateMeOutputBody":{"additionalProperties":true,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["/api/v1/schemas/UpdateMeOutputBody.json"],"format":"uri","readOnly":true,"type":"string"},"email":{"type":"string"}},"required":["email"],"type":"object"}},"securitySchemes":{"bearerAuth":{"bearerFormat":"JWT","description":"Bearer token minted by entire-core's device-code flow or STS exchange.","scheme":"bearer","type":"http"},"sessionAuth":{"description":"Console session cookie issued by the browser login flow.","in":"cookie","name":"entire_session","type":"apiKey"}}},"info":{"description":"Entire control plane: identity, orgs, projects, repos, mirrors, service accounts.","title":"Entire Core API","version":"1.0.0"},"openapi":"3.1.0","paths":{"/access/{resourceType}":{"get":{"operationId":"lookupResources","parameters":[{"description":"Maximum entries to return; server may cap further.","explode":false,"in":"query","name":"pageSize","schema":{"description":"Maximum entries to return; server may cap further.","format":"int32","maximum":500,"minimum":0,"type":"integer"}},{"description":"Opaque cursor from a previous response's nextPageToken.","explode":false,"in":"query","name":"pageToken","schema":{"description":"Opaque cursor from a previous response's nextPageToken.","type":"string"}},{"description":"SpiceDB resource type (e.g. \"repo\", \"project\", \"org\").","in":"path","name":"resourceType","required":true,"schema":{"description":"SpiceDB resource type (e.g. \"repo\", \"project\", \"org\").","minLength":1,"type":"string"}},{"description":"Optional: only list resources where the caller has this permission. pageSize/pageToken apply only when set.","explode":false,"in":"query","name":"permission","schema":{"description":"Optional: only list resources where the caller has this permission. pageSize/pageToken apply only when set.","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LookupResourcesOutputBody"}}},"description":"OK"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"List resources of a type the caller can access","tags":["identity"]}},"/access/{resourceType}/{resourceId}":{"get":{"operationId":"getPermissions","parameters":[{"in":"path","name":"resourceType","required":true,"schema":{"minLength":1,"type":"string"}},{"in":"path","name":"resourceId","required":true,"schema":{"minLength":1,"type":"string"}},{"description":"If set, return the SpiceDB trace for this permission instead of the permission list.","explode":false,"in":"query","name":"explain","schema":{"description":"If set, return the SpiceDB trace for this permission instead of the permission list.","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetPermissionsOutputBody"}}},"description":"OK"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"List the caller's permissions on a single resource","tags":["identity"]}},"/audit":{"get":{"operationId":"listAuditEvents","parameters":[{"description":"Maximum entries to return; server may cap further.","explode":false,"in":"query","name":"pageSize","schema":{"description":"Maximum entries to return; server may cap further.","format":"int32","maximum":500,"minimum":0,"type":"integer"}},{"description":"Opaque cursor from a previous response's nextPageToken.","explode":false,"in":"query","name":"pageToken","schema":{"description":"Opaque cursor from a previous response's nextPageToken.","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListAuditEventsOutputBody"}}},"description":"OK"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"List the calling account's recent audit events","tags":["identity"]}},"/clusters":{"get":{"operationId":"listClusters","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListClustersOutputBody"}}},"description":"OK"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"List data-plane clusters attached to this control plane","tags":["clusters"]}},"/identity/handles/{provider}/{handle}":{"get":{"operationId":"resolveHandle","parameters":[{"description":"IdP slug (e.g. \"github\").","in":"path","name":"provider","required":true,"schema":{"description":"IdP slug (e.g. \"github\").","minLength":1,"type":"string"}},{"description":"User-visible handle at the provider.","in":"path","name":"handle","required":true,"schema":{"description":"User-visible handle at the provider.","minLength":1,"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResolvedIdentity"}}},"description":"OK"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Resolve account by external provider handle","tags":["identity"]}},"/lookup":{"post":{"operationId":"batchLookup","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchLookupInputBody"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchLookupOutputBody"}}},"description":"OK"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Batch-resolve (type, id) refs to enriched records","tags":["identity"]}},"/me":{"get":{"operationId":"getMe","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetMeOutputBody"}}},"description":"OK"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Get the calling account's identity and profile","tags":["identity"]},"patch":{"operationId":"updateMe","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMeInputBody"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMeOutputBody"}}},"description":"OK"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Update the calling account's contact email","tags":["identity"]}},"/mirrors":{"delete":{"operationId":"deleteMirror","parameters":[{"explode":false,"in":"query","name":"provider","required":true,"schema":{"enum":["github"],"type":"string"}},{"explode":false,"in":"query","name":"owner","required":true,"schema":{"minLength":1,"type":"string"}},{"explode":false,"in":"query","name":"repo","required":true,"schema":{"minLength":1,"type":"string"}},{"description":"Public host of the cluster serving the mirror.","explode":false,"in":"query","name":"clusterHost","required":true,"schema":{"description":"Public host of the cluster serving the mirror.","minLength":1,"type":"string"}}],"responses":{"204":{"description":"No Content"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"421":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Misdirected Request"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"},"502":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Gateway"},"503":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Service Unavailable"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Delete a mirror by upstream coords + cluster host","tags":["mirrors"]},"get":{"operationId":"listMirrors","parameters":[{"description":"Maximum entries to return; server may cap further.","explode":false,"in":"query","name":"pageSize","schema":{"description":"Maximum entries to return; server may cap further.","format":"int32","maximum":500,"minimum":0,"type":"integer"}},{"description":"Opaque cursor from a previous response's nextPageToken.","explode":false,"in":"query","name":"pageToken","schema":{"description":"Opaque cursor from a previous response's nextPageToken.","type":"string"}},{"description":"Optional: restrict to mirrors on this cluster (public host, e.g. royalcanin.partial.to). Case-sensitive exact match.","explode":false,"in":"query","name":"cluster","schema":{"description":"Optional: restrict to mirrors on this cluster (public host, e.g. royalcanin.partial.to). Case-sensitive exact match.","type":"string"}},{"description":"Optional: restrict to mirrors of this upstream provider, case-insensitive (e.g. \"github\").","explode":false,"in":"query","name":"provider","schema":{"description":"Optional: restrict to mirrors of this upstream provider, case-insensitive (e.g. \"github\").","type":"string"}},{"description":"Optional: restrict to mirrors with this upstream owner login (case-insensitive).","explode":false,"in":"query","name":"owner","schema":{"description":"Optional: restrict to mirrors with this upstream owner login (case-insensitive).","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListMirrorsOutputBody"}}},"description":"OK"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"List mirrors visible to the caller","tags":["mirrors"]},"post":{"operationId":"createMirror","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateMirrorInputBody"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatedMirror"}}},"description":"Created"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Conflict"},"412":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Precondition Failed"},"421":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Misdirected Request"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"},"502":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Gateway"},"503":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Service Unavailable"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Create GitHub mirror","tags":["mirrors"]}},"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/mirrors/available":{"get":{"operationId":"listAvailableMirrors","parameters":[{"description":"Optional: restrict to repos with this owner login (case-insensitive).","explode":false,"in":"query","name":"owner","schema":{"description":"Optional: restrict to repos with this owner login (case-insensitive).","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListAvailableMirrorsOutputBody"}}},"description":"OK"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"},"502":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Gateway"},"503":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Service Unavailable"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"List GitHub repos the caller could onboard as mirrors","tags":["mirrors"]}},"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/mirrors/collaborators":{"delete":{"operationId":"revokeMirrorCollaborator","parameters":[{"explode":false,"in":"query","name":"provider","required":true,"schema":{"enum":["github"],"type":"string"}},{"explode":false,"in":"query","name":"owner","required":true,"schema":{"minLength":1,"type":"string"}},{"explode":false,"in":"query","name":"repo","required":true,"schema":{"minLength":1,"type":"string"}},{"description":"Public host of the cluster serving the mirror.","explode":false,"in":"query","name":"clusterHost","required":true,"schema":{"description":"Public host of the cluster serving the mirror.","minLength":1,"type":"string"}},{"description":"Qualified grantee handle, e.g. github:alice.","explode":false,"in":"query","name":"handle","required":true,"schema":{"description":"Qualified grantee handle, e.g. github:alice.","minLength":1,"type":"string"}}],"responses":{"204":{"description":"No Content"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"421":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Misdirected Request"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"},"502":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Gateway"},"503":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Service Unavailable"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Revoke a user's access to a mirror (live GitHub-admin gated)","tags":["mirrors"]},"get":{"operationId":"listMirrorCollaborators","parameters":[{"explode":false,"in":"query","name":"provider","required":true,"schema":{"enum":["github"],"type":"string"}},{"explode":false,"in":"query","name":"owner","required":true,"schema":{"minLength":1,"type":"string"}},{"explode":false,"in":"query","name":"repo","required":true,"schema":{"minLength":1,"type":"string"}},{"description":"Public host of the cluster serving the mirror.","explode":false,"in":"query","name":"clusterHost","required":true,"schema":{"description":"Public host of the cluster serving the mirror.","minLength":1,"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListMirrorCollaboratorsOutputBody"}}},"description":"OK"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"421":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Misdirected Request"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"},"502":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Gateway"},"503":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Service Unavailable"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"List the principals with access to a mirror (live GitHub-admin gated)","tags":["mirrors"]},"post":{"operationId":"grantMirrorCollaborator","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GrantMirrorCollaboratorInputBody"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GrantedMirrorCollaborator"}}},"description":"OK"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Conflict"},"421":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Misdirected Request"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"},"502":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Gateway"},"503":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Service Unavailable"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Grant a user reader/writer access to a mirror (live GitHub-admin gated)","tags":["mirrors"]}},"/mirrors/{mirrorId}":{"get":{"operationId":"getMirror","parameters":[{"in":"path","name":"mirrorId","required":true,"schema":{"pattern":"^[0-9A-HJKMNP-TV-Z]{26}$","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Mirror"}}},"description":"OK"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Get mirror by id","tags":["mirrors"]}},"/oidc-providers":{"get":{"operationId":"listOIDCProviders","parameters":[{"description":"Maximum entries to return; server may cap further.","explode":false,"in":"query","name":"pageSize","schema":{"description":"Maximum entries to return; server may cap further.","format":"int32","maximum":500,"minimum":0,"type":"integer"}},{"description":"Opaque cursor from a previous response's nextPageToken.","explode":false,"in":"query","name":"pageToken","schema":{"description":"Opaque cursor from a previous response's nextPageToken.","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListOIDCProvidersOutputBody"}}},"description":"OK"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"},"503":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Service Unavailable"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"List federated OIDC identity providers","tags":["identity"]}},"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/orgs":{"get":{"operationId":"listOrgs","parameters":[{"description":"Maximum entries to return; server may cap further.","explode":false,"in":"query","name":"pageSize","schema":{"description":"Maximum entries to return; server may cap further.","format":"int32","maximum":500,"minimum":0,"type":"integer"}},{"description":"Opaque cursor from a previous response's nextPageToken.","explode":false,"in":"query","name":"pageToken","schema":{"description":"Opaque cursor from a previous response's nextPageToken.","type":"string"}},{"description":"Optional: exact-match org name (case-insensitive).","explode":false,"in":"query","name":"name","schema":{"description":"Optional: exact-match org name (case-insensitive).","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListOrgsOutputBody"}}},"description":"OK"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"List organizations the caller can see (or one by name)","tags":["orgs"]},"post":{"operationId":"createOrg","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateOrgInputBody"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Org"}}},"description":"Created"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Conflict"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Create organization","tags":["orgs"]}},"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/orgs/{orgId}":{"delete":{"operationId":"deleteOrg","parameters":[{"in":"path","name":"orgId","required":true,"schema":{"pattern":"^[0-9A-HJKMNP-TV-Z]{26}$","type":"string"}}],"responses":{"204":{"description":"No Content"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Conflict"},"421":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Misdirected Request"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Delete an organization","tags":["orgs"]},"get":{"operationId":"getOrg","parameters":[{"in":"path","name":"orgId","required":true,"schema":{"pattern":"^[0-9A-HJKMNP-TV-Z]{26}$","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Org"}}},"description":"OK"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Get an organization","tags":["orgs"]}},"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/orgs/{orgId}/members":{"get":{"operationId":"listOrgMembers","parameters":[{"description":"Maximum entries to return; server may cap further.","explode":false,"in":"query","name":"pageSize","schema":{"description":"Maximum entries to return; server may cap further.","format":"int32","maximum":500,"minimum":0,"type":"integer"}},{"description":"Opaque cursor from a previous response's nextPageToken.","explode":false,"in":"query","name":"pageToken","schema":{"description":"Opaque cursor from a previous response's nextPageToken.","type":"string"}},{"in":"path","name":"orgId","required":true,"schema":{"pattern":"^[0-9A-HJKMNP-TV-Z]{26}$","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListOrgMembersOutputBody"}}},"description":"OK"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"List members of an organization","tags":["orgs"]},"post":{"operationId":"addOrgMember","parameters":[{"in":"path","name":"orgId","required":true,"schema":{"pattern":"^[0-9A-HJKMNP-TV-Z]{26}$","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddOrgMemberInputBody"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Membership"}}},"description":"Created"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Add a member to an organization","tags":["orgs"]}},"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/orgs/{orgId}/members/{provider}/{providerUserId}":{"delete":{"operationId":"removeOrgMember","parameters":[{"in":"path","name":"orgId","required":true,"schema":{"pattern":"^[0-9A-HJKMNP-TV-Z]{26}$","type":"string"}},{"in":"path","name":"provider","required":true,"schema":{"minLength":1,"type":"string"}},{"in":"path","name":"providerUserId","required":true,"schema":{"minLength":1,"type":"string"}}],"responses":{"204":{"description":"No Content"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Remove a member from an organization","tags":["orgs"]}},"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/orgs/{orgId}/projects":{"get":{"operationId":"listOrgProjects","parameters":[{"description":"Maximum entries to return; server may cap further.","explode":false,"in":"query","name":"pageSize","schema":{"description":"Maximum entries to return; server may cap further.","format":"int32","maximum":500,"minimum":0,"type":"integer"}},{"description":"Opaque cursor from a previous response's nextPageToken.","explode":false,"in":"query","name":"pageToken","schema":{"description":"Opaque cursor from a previous response's nextPageToken.","type":"string"}},{"in":"path","name":"orgId","required":true,"schema":{"pattern":"^[0-9A-HJKMNP-TV-Z]{26}$","type":"string"}},{"description":"Optional: exact-match project name (case-insensitive).","explode":false,"in":"query","name":"name","schema":{"description":"Optional: exact-match project name (case-insensitive).","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListOrgProjectsOutputBody"}}},"description":"OK"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"List projects owned by an organization","tags":["projects"]}},"/projects":{"get":{"operationId":"listProjects","parameters":[{"description":"Maximum entries to return; server may cap further.","explode":false,"in":"query","name":"pageSize","schema":{"description":"Maximum entries to return; server may cap further.","format":"int32","maximum":500,"minimum":0,"type":"integer"}},{"description":"Opaque cursor from a previous response's nextPageToken.","explode":false,"in":"query","name":"pageToken","schema":{"description":"Opaque cursor from a previous response's nextPageToken.","type":"string"}},{"description":"Optional: exact-match project name (case-insensitive).","explode":false,"in":"query","name":"name","schema":{"description":"Optional: exact-match project name (case-insensitive).","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListProjectsOutputBody"}}},"description":"OK"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"List projects accessible to the caller (or one by name)","tags":["projects"]},"post":{"operationId":"createProject","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProjectInputBody"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Project"}}},"description":"Created"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Conflict"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Create project","tags":["projects"]}},"/projects/{projectId}":{"delete":{"operationId":"deleteProject","parameters":[{"in":"path","name":"projectId","required":true,"schema":{"pattern":"^[0-9A-HJKMNP-TV-Z]{26}$","type":"string"}}],"responses":{"204":{"description":"No Content"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Conflict"},"421":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Misdirected Request"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Delete a project","tags":["projects"]},"get":{"operationId":"getProject","parameters":[{"in":"path","name":"projectId","required":true,"schema":{"pattern":"^[0-9A-HJKMNP-TV-Z]{26}$","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Project"}}},"description":"OK"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Get a project by id","tags":["projects"]}},"/projects/{projectId}/grants":{"post":{"operationId":"grantProjectAccess","parameters":[{"in":"path","name":"projectId","required":true,"schema":{"pattern":"^[0-9A-HJKMNP-TV-Z]{26}$","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GrantProjectAccessInputBody"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GrantProjectAccessOutputBody"}}},"description":"Created"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Conflict"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Grant project access to an identity","tags":["projects"]}},"/projects/{projectId}/grants/account/{provider}/{providerUserId}":{"delete":{"operationId":"revokeProjectAccessByProvider","parameters":[{"in":"path","name":"projectId","required":true,"schema":{"pattern":"^[0-9A-HJKMNP-TV-Z]{26}$","type":"string"}},{"in":"path","name":"provider","required":true,"schema":{"minLength":1,"type":"string"}},{"in":"path","name":"providerUserId","required":true,"schema":{"minLength":1,"type":"string"}}],"responses":{"204":{"description":"No Content"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Revoke project access by provider identity","tags":["projects"]}},"/projects/{projectId}/grants/{granteeType}/{granteeId}":{"delete":{"operationId":"revokeProjectAccess","parameters":[{"in":"path","name":"projectId","required":true,"schema":{"pattern":"^[0-9A-HJKMNP-TV-Z]{26}$","type":"string"}},{"in":"path","name":"granteeType","required":true,"schema":{"minLength":1,"type":"string"}},{"in":"path","name":"granteeId","required":true,"schema":{"minLength":1,"type":"string"}}],"responses":{"204":{"description":"No Content"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Revoke project access by grantee id","tags":["projects"]}},"/projects/{projectId}/members":{"get":{"operationId":"listProjectMembers","parameters":[{"description":"Maximum entries to return; server may cap further.","explode":false,"in":"query","name":"pageSize","schema":{"description":"Maximum entries to return; server may cap further.","format":"int32","maximum":500,"minimum":0,"type":"integer"}},{"description":"Opaque cursor from a previous response's nextPageToken.","explode":false,"in":"query","name":"pageToken","schema":{"description":"Opaque cursor from a previous response's nextPageToken.","type":"string"}},{"in":"path","name":"projectId","required":true,"schema":{"pattern":"^[0-9A-HJKMNP-TV-Z]{26}$","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListProjectMembersOutputBody"}}},"description":"OK"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"List project members and their roles","tags":["projects"]}},"/projects/{projectId}/repos":{"get":{"operationId":"listProjectRepos","parameters":[{"description":"Maximum entries to return; server may cap further.","explode":false,"in":"query","name":"pageSize","schema":{"description":"Maximum entries to return; server may cap further.","format":"int32","maximum":500,"minimum":0,"type":"integer"}},{"description":"Opaque cursor from a previous response's nextPageToken.","explode":false,"in":"query","name":"pageToken","schema":{"description":"Opaque cursor from a previous response's nextPageToken.","type":"string"}},{"in":"path","name":"projectId","required":true,"schema":{"pattern":"^[0-9A-HJKMNP-TV-Z]{26}$","type":"string"}},{"description":"Optional: exact-match repo name (case-insensitive).","explode":false,"in":"query","name":"name","schema":{"description":"Optional: exact-match repo name (case-insensitive).","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListProjectReposOutputBody"}}},"description":"OK"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"List repositories in a project (or one by name)","tags":["repos"]}},"/repos":{"post":{"operationId":"createRepo","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateRepoInputBody"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Repo"}}},"description":"Created"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Conflict"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"},"503":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Service Unavailable"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Create repository","tags":["repos"]}},"/repos/{repoId}":{"delete":{"operationId":"deleteRepo","parameters":[{"in":"path","name":"repoId","required":true,"schema":{"pattern":"^[0-9A-HJKMNP-TV-Z]{26}$","type":"string"}}],"responses":{"204":{"description":"No Content"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"421":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Misdirected Request"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"},"502":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Gateway"},"503":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Service Unavailable"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Delete repository","tags":["repos"]},"get":{"operationId":"getRepo","parameters":[{"in":"path","name":"repoId","required":true,"schema":{"pattern":"^[0-9A-HJKMNP-TV-Z]{26}$","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Repo"}}},"description":"OK"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Get repository","tags":["repos"]}},"/repos/{repoId}/grants":{"get":{"operationId":"listRepoGrants","parameters":[{"description":"Maximum entries to return; server may cap further.","explode":false,"in":"query","name":"pageSize","schema":{"description":"Maximum entries to return; server may cap further.","format":"int32","maximum":500,"minimum":0,"type":"integer"}},{"description":"Opaque cursor from a previous response's nextPageToken.","explode":false,"in":"query","name":"pageToken","schema":{"description":"Opaque cursor from a previous response's nextPageToken.","type":"string"}},{"in":"path","name":"repoId","required":true,"schema":{"pattern":"^[0-9A-HJKMNP-TV-Z]{26}$","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListRepoGrantsOutputBody"}}},"description":"OK"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"List repo grants","tags":["repos"]},"post":{"operationId":"grantRepoAccess","parameters":[{"in":"path","name":"repoId","required":true,"schema":{"pattern":"^[0-9A-HJKMNP-TV-Z]{26}$","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GrantRepoAccessInputBody"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GrantRepoAccessOutputBody"}}},"description":"Created"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Conflict"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Grant repo access to an identity","tags":["repos"]}},"/repos/{repoId}/grants/account/{provider}/{providerUserId}":{"delete":{"operationId":"revokeRepoAccessByProvider","parameters":[{"in":"path","name":"repoId","required":true,"schema":{"pattern":"^[0-9A-HJKMNP-TV-Z]{26}$","type":"string"}},{"in":"path","name":"provider","required":true,"schema":{"minLength":1,"type":"string"}},{"in":"path","name":"providerUserId","required":true,"schema":{"minLength":1,"type":"string"}}],"responses":{"204":{"description":"No Content"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Revoke repo access by provider identity","tags":["repos"]}},"/repos/{repoId}/grants/{granteeType}/{granteeId}":{"delete":{"operationId":"revokeRepoAccess","parameters":[{"in":"path","name":"repoId","required":true,"schema":{"pattern":"^[0-9A-HJKMNP-TV-Z]{26}$","type":"string"}},{"in":"path","name":"granteeType","required":true,"schema":{"minLength":1,"type":"string"}},{"in":"path","name":"granteeId","required":true,"schema":{"minLength":1,"type":"string"}}],"responses":{"204":{"description":"No Content"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Revoke repo access by grantee id","tags":["repos"]}},"/repos/{repoId}/visibility":{"get":{"operationId":"getRepoVisibility","parameters":[{"in":"path","name":"repoId","required":true,"schema":{"pattern":"^[0-9A-HJKMNP-TV-Z]{26}$","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetRepoVisibilityOutputBody"}}},"description":"OK"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Get repository visibility","tags":["repos"]},"put":{"operationId":"setRepoVisibility","parameters":[{"in":"path","name":"repoId","required":true,"schema":{"pattern":"^[0-9A-HJKMNP-TV-Z]{26}$","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetRepoVisibilityInputBody"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetRepoVisibilityOutputBody"}}},"description":"OK"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Set repository visibility","tags":["repos"]}},"/service-accounts":{"get":{"operationId":"listServiceAccounts","parameters":[{"description":"Maximum entries to return; server may cap further.","explode":false,"in":"query","name":"pageSize","schema":{"description":"Maximum entries to return; server may cap further.","format":"int32","maximum":500,"minimum":0,"type":"integer"}},{"description":"Opaque cursor from a previous response's nextPageToken.","explode":false,"in":"query","name":"pageToken","schema":{"description":"Opaque cursor from a previous response's nextPageToken.","type":"string"}},{"explode":false,"in":"query","name":"orgId","required":true,"schema":{"pattern":"^[0-9A-HJKMNP-TV-Z]{26}$","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListServiceAccountsOutputBody"}}},"description":"OK"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"},"503":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Service Unavailable"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"List service accounts in an org","tags":["service-accounts"]},"post":{"operationId":"createServiceAccount","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateServiceAccountInputBody"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceAccount"}}},"description":"Created"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Conflict"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"},"503":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Service Unavailable"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Create service account","tags":["service-accounts"]}},"/service-accounts/{accountId}":{"delete":{"operationId":"deleteServiceAccount","parameters":[{"in":"path","name":"accountId","required":true,"schema":{"minLength":1,"type":"string"}}],"responses":{"204":{"description":"No Content"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"},"503":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Service Unavailable"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Delete service account","tags":["service-accounts"]},"get":{"operationId":"getServiceAccount","parameters":[{"in":"path","name":"accountId","required":true,"schema":{"minLength":1,"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceAccount"}}},"description":"OK"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"},"503":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Service Unavailable"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Get service account","tags":["service-accounts"]}},"/service-accounts/{accountId}/bindings":{"get":{"operationId":"listBindings","parameters":[{"description":"Maximum entries to return; server may cap further.","explode":false,"in":"query","name":"pageSize","schema":{"description":"Maximum entries to return; server may cap further.","format":"int32","maximum":500,"minimum":0,"type":"integer"}},{"description":"Opaque cursor from a previous response's nextPageToken.","explode":false,"in":"query","name":"pageToken","schema":{"description":"Opaque cursor from a previous response's nextPageToken.","type":"string"}},{"in":"path","name":"accountId","required":true,"schema":{"minLength":1,"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListBindingsOutputBody"}}},"description":"OK"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"},"503":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Service Unavailable"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"List OIDC bindings","tags":["service-accounts"]},"post":{"operationId":"createBinding","parameters":[{"in":"path","name":"accountId","required":true,"schema":{"minLength":1,"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateBindingInputBody"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Binding"}}},"description":"Created"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Conflict"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"},"503":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Service Unavailable"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Create OIDC binding","tags":["service-accounts"]}},"/service-accounts/{accountId}/bindings/{bindingId}":{"delete":{"operationId":"deleteBinding","parameters":[{"in":"path","name":"accountId","required":true,"schema":{"minLength":1,"type":"string"}},{"in":"path","name":"bindingId","required":true,"schema":{"minLength":1,"type":"string"}}],"responses":{"204":{"description":"No Content"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"},"503":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Service Unavailable"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Delete OIDC binding","tags":["service-accounts"]}},"/service-accounts/{accountId}/grants":{"get":{"operationId":"listServiceAccountGrants","parameters":[{"description":"Maximum entries to return; server may cap further.","explode":false,"in":"query","name":"pageSize","schema":{"description":"Maximum entries to return; server may cap further.","format":"int32","maximum":500,"minimum":0,"type":"integer"}},{"description":"Opaque cursor from a previous response's nextPageToken.","explode":false,"in":"query","name":"pageToken","schema":{"description":"Opaque cursor from a previous response's nextPageToken.","type":"string"}},{"in":"path","name":"accountId","required":true,"schema":{"minLength":1,"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListServiceAccountGrantsOutputBody"}}},"description":"OK"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"},"503":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Service Unavailable"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"List service account grants","tags":["service-accounts"]},"post":{"operationId":"grantServiceAccountAccess","parameters":[{"in":"path","name":"accountId","required":true,"schema":{"minLength":1,"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GrantServiceAccountAccessInputBody"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GrantServiceAccountAccessOutputBody"}}},"description":"Created"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Conflict"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"},"503":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Service Unavailable"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Grant service account access on a repo or project","tags":["service-accounts"]}},"/service-accounts/{accountId}/grants/{resourceType}/{resourceId}":{"delete":{"operationId":"revokeServiceAccountAccess","parameters":[{"in":"path","name":"accountId","required":true,"schema":{"minLength":1,"type":"string"}},{"in":"path","name":"resourceType","required":true,"schema":{"enum":["repo","project"],"type":"string"}},{"in":"path","name":"resourceId","required":true,"schema":{"minLength":1,"type":"string"}}],"responses":{"204":{"description":"No Content"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Forbidden"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"},"503":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Service Unavailable"}},"security":[{"bearerAuth":[]},{"sessionAuth":[]}],"summary":"Revoke service account access","tags":["service-accounts"]}},"/version":{"get":{"operationId":"getVersion","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetVersionOutputBody"}}},"description":"OK"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"summary":"Get the server version and mode","tags":["meta"]}}},"servers":[{"url":"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/api/v1"}]} \ No newline at end of file From 08a1c7df19ce2eec7715eb82a56c749095589fa9 Mon Sep 17 00:00:00 2001 From: paul <423357+toothbrush@users.noreply.github.com> Date: Sun, 28 Jun 2026 21:18:36 +0930 Subject: [PATCH 4/5] fix(grant): reject ULID grantee with a clear message in resolveGranteeProvider MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `grant … list` now prints the grantee ID column, so users naturally paste a ULID into `grant … add`. The by-provider routes can't be addressed by ULID, and the shared parseQualifiedHandle error dangled a "(or a ULID)" hint that only applies to the account-ref/remove paths. Guard the ULID case up front with a message that points at the provider:handle form this command wants. Addresses Cursor Bugbot + Copilot review findings on #1549. Co-Authored-By: Claude Opus 4.8 (1M context) --- cmd/entire/cli/resolveref.go | 7 +++++++ cmd/entire/cli/resolveref_test.go | 18 ++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/cmd/entire/cli/resolveref.go b/cmd/entire/cli/resolveref.go index 213c1e6d15..faade3b0b1 100644 --- a/cmd/entire/cli/resolveref.go +++ b/cmd/entire/cli/resolveref.go @@ -113,6 +113,13 @@ func resolveAccountRef(ctx context.Context, c *coreapi.Client, ref string) (stri // account→provider-id lookup; callers that accept a ULID grantee (project/repo // remove) handle it via the typed-id route before reaching this helper. func resolveGranteeProvider(ctx context.Context, c *coreapi.Client, ref string) (provider, providerUserID string, err error) { + // A ULID is a tempting paste from `grant … list` (which prints the grantee + // ID), but the by-provider routes can't be addressed by ULID. Reject it with + // a message that points at the form this command actually wants, rather than + // letting parseQualifiedHandle dangle a "(or a ULID)" hint that doesn't apply. + if looksLikeULID(ref) { + return "", "", fmt.Errorf("grantee %q is an account ULID; this command needs a provider-qualified handle like \"github:alice\"", ref) + } p, handle, err := parseQualifiedHandle(ref) if err != nil { return "", "", err diff --git a/cmd/entire/cli/resolveref_test.go b/cmd/entire/cli/resolveref_test.go index a36d26f76a..5f15465d82 100644 --- a/cmd/entire/cli/resolveref_test.go +++ b/cmd/entire/cli/resolveref_test.go @@ -347,6 +347,24 @@ func TestResolveGranteeProvider(t *testing.T) { } }) + t.Run("account ULID is rejected before any network call", func(t *testing.T) { + t.Parallel() + c, calls := resolveTestClient(t, func(w http.ResponseWriter, _ *http.Request) { + t.Error("unexpected HTTP call for a ULID grantee") + w.WriteHeader(http.StatusInternalServerError) + }) + _, _, err := resolveGranteeProvider(context.Background(), c, wiringGranteeULID) + if err == nil { + t.Fatal("resolveGranteeProvider expected error for a ULID grantee") + } + if !strings.Contains(err.Error(), "provider-qualified handle") { + t.Errorf("error %q should point at the provider-qualified handle form", err) + } + if n := calls.Load(); n != 0 { + t.Errorf("ULID grantee made %d HTTP calls, want 0", n) + } + }) + t.Run("empty provider user id is an error", func(t *testing.T) { t.Parallel() c, _ := resolveTestClient(t, func(w http.ResponseWriter, _ *http.Request) { From 8dc7a2ff15b460eeb1999819e4c788999d15805f Mon Sep 17 00:00:00 2001 From: paul <423357+toothbrush@users.noreply.github.com> Date: Mon, 29 Jun 2026 12:08:53 +0930 Subject: [PATCH 5/5] refactor(grant): share revoke routing; test granteeName + grant rows Extract the ULID-vs-handle revoke routing and message formatting shared by revokeProjectGrantee/revokeRepoGrantee into revokeGrantee. Add tests for granteeName's name/ULID fallback and the project/repo grant row builders. Co-Authored-By: Claude Opus 4.8 (1M context) Entire-Checkpoint: 2a9100f0081f --- cmd/entire/cli/grant.go | 70 +++++++++++++++++++++--------------- cmd/entire/cli/grant_test.go | 65 +++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+), 29 deletions(-) diff --git a/cmd/entire/cli/grant.go b/cmd/entire/cli/grant.go index 653e08ffe3..b4dd6538f3 100644 --- a/cmd/entire/cli/grant.go +++ b/cmd/entire/cli/grant.go @@ -301,30 +301,48 @@ func newGrantProjectRemoveCmd() *cobra.Command { } // 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. +// a resolved project. 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 revokeGrantee(ctx, cmd, c, "project", projectRef, grantee, + func() error { return c.RevokeProjectAccess(ctx, coreapi.RevokeProjectAccessParams{ ProjectId: projID, GranteeType: "account", GranteeId: grantee, }) + }, + func(provider, providerUserID string) error { + return c.RevokeProjectAccessByProvider(ctx, coreapi.RevokeProjectAccessByProviderParams{ + ProjectId: projID, + Provider: provider, + ProviderUserId: providerUserID, + }) }) +} + +// revokeGrantee performs the shared grantee-revocation routing for projects and +// repos: a ULID grantee takes the typed-id route (revokeByID); a provider:handle +// is resolved to its provider account first and takes the by-provider route +// (revokeByProvider). target ("project"/"repo") and ref name the grant in the +// success message. +func revokeGrantee( + ctx context.Context, + cmd *cobra.Command, + c *coreapi.Client, + target, ref, grantee string, + revokeByID func() error, + revokeByProvider func(provider, providerUserID string) error, +) error { + if looksLikeULID(grantee) { + return revokeGrant(cmd, "Revoked", fmt.Sprintf("account %s from %s %s", grantee, target, ref), revokeByID) } 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, - }) + return revokeGrant(cmd, "Revoked", fmt.Sprintf("%s from %s %s", grantee, target, ref), func() error { + return revokeByProvider(provider, providerUserID) }) } @@ -432,30 +450,24 @@ func newGrantRepoRemoveCmd() *cobra.Command { return cmd } -// 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. +// revokeRepoGrantee mirrors revokeProjectGrantee for repos. 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 revokeGrantee(ctx, cmd, c, "repo", repoRef, grantee, + func() error { return c.RevokeRepoAccess(ctx, coreapi.RevokeRepoAccessParams{ RepoId: repoID, GranteeType: "account", GranteeId: grantee, }) + }, + func(provider, providerUserID string) error { + return c.RevokeRepoAccessByProvider(ctx, coreapi.RevokeRepoAccessByProviderParams{ + RepoId: repoID, + Provider: provider, + ProviderUserId: providerUserID, + }) }) - } - 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 diff --git a/cmd/entire/cli/grant_test.go b/cmd/entire/cli/grant_test.go index 0bab40d231..354b658e64 100644 --- a/cmd/entire/cli/grant_test.go +++ b/cmd/entire/cli/grant_test.go @@ -1,6 +1,7 @@ package cli import ( + "slices" "testing" "github.com/entireio/cli/internal/coreapi" @@ -20,6 +21,70 @@ func TestValidateGrantRole(t *testing.T) { } } +func TestGranteeName(t *testing.T) { + t.Parallel() + const ulid = "01HZX0000000000000000000AB" + tests := []struct { + name string + in coreapi.OptString + id string + want string + }{ + {name: "friendly name wins", in: coreapi.NewOptString("github:alice"), id: ulid, want: "github:alice"}, + {name: "unset falls back to ULID", in: coreapi.OptString{}, id: ulid, want: ulid}, + {name: "empty string falls back to ULID", in: coreapi.NewOptString(""), id: ulid, want: ulid}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + if got := granteeName(tt.in, tt.id); got != tt.want { + t.Errorf("granteeName(%v, %q) = %q, want %q", tt.in, tt.id, got, tt.want) + } + }) + } +} + +func TestGrantRows(t *testing.T) { + t.Parallel() + const ulid = "01HZX0000000000000000000AB" + + // grantColumns and the row builders must stay in lockstep — same width, + // same column order — or the table header and cells misalign. + if got, want := len(grantColumns), 5; got != want { + t.Fatalf("grantColumns has %d columns, want %d", got, want) + } + + t.Run("project resolved name", func(t *testing.T) { + t.Parallel() + row := projectGrantRow(coreapi.ProjectGrant{ + GranteeId: ulid, + GranteeName: coreapi.NewOptString("github:alice"), + GranteeType: "account", + Role: "writer", + Source: "direct", + }) + want := []string{"account", "github:alice", ulid, "writer", "direct"} + if !slices.Equal(row, want) { + t.Errorf("projectGrantRow = %v, want %v", row, want) + } + }) + + t.Run("repo unresolved name falls back to ULID", func(t *testing.T) { + t.Parallel() + row := repoGrantRow(coreapi.RepoGrant{ + GranteeId: ulid, + GranteeName: coreapi.OptString{}, + GranteeType: "team", + Role: "reader", + Source: "inherited", + }) + want := []string{"team", ulid, ulid, "reader", "inherited"} + if !slices.Equal(row, want) { + t.Errorf("repoGrantRow = %v, want %v", row, want) + } + }) +} + func TestParseOrgRole(t *testing.T) { t.Parallel() tests := []struct {