Skip to content

[CXH-2123] - Add provisioning for the Enterprise Owner role - GitHub Connector - #194

Open
mateoHernandez123 wants to merge 28 commits into
mainfrom
mateoHernandez123/github-enterprise-owner-provisioning
Open

mateoHernandez123 wants to merge 28 commits into
mainfrom
mateoHernandez123/github-enterprise-owner-provisioning

Conversation

@mateoHernandez123

@mateoHernandez123 mateoHernandez123 commented Sep 22, 2026 •

Copy link
Copy Markdown
Contributor

Description

  • Bug fix
  • New feature

Adds Grant and Revoke for the built-in Enterprise Owner role under GitHub App authentication, which CXH-2123 asks for on behalf of DoorDash: they want that role requestable and time-bound from C1.

The ticket's implementation note pointed at a GraphQL mutation called updateEnterpriseOwnerMembership. That mutation does not exist, and the real model is more involved: GitHub has no single operation that assigns Owner. A member becomes one by accepting an invitation, and GitHub rejects that invitation outright when the user already holds an enterprise administrator role such as Billing manager. An installation token cannot read that prior role — Enterprise.ownerInfo resolves to null — so the connector refuses that case with FailedPrecondition rather than promoting in place: Revoke could only demote to UNAFFILIATED, discarding a role the grant never gave. I corrected the ticket description with what the API actually offers.

Contrary to the original support thread, this does not require a personal access token. It works with a GitHub App installed on both the enterprise account and the organization.

Sync:

  • Enterprise roles (enterprise_role) — under GitHub App authentication the connector now lists the built-in Owner role and emits its grants. Owners are read from Organization.enterpriseOwners with the organization installation token; Enterprise.members(role: OWNER) looks like the right field but returns owners of organizations inside the enterprise, not owners of the enterprise account. Under PAT authentication the resource type is unchanged.
  • Pending invitations are emitted as grants on the same assigned entitlement as accepted owners. C1 has no pending state for a grant, so an invitee is indistinguishable from a real owner until they accept or the invitation lapses. That is a deliberate trade: emitting nothing would leave the request invisible in C1 for up to seven days with no record that it was made. An access review or offboarding sweep will count an invitee as holding Owner — documented in docs/docs-info.md and in the enterprise connector docs.
  • Every other resource type is an unchanged surface.

Provisioning:

  • Grant/Revoke Enterprise Owner (NEW) — Grant invites. A user GitHub refuses to invite, because they already hold an administrator role, is rejected rather than promoted in place, since the prior role is unreadable and Revoke would discard it. Revoke clears both states rather than treating them as alternatives: it demotes an active owner to UNAFFILIATED, which keeps their enterprise membership instead of evicting them, and cancels an unaccepted invitation.
  • Idempotency: GrantAlreadyExists when the user already holds the role or already has a pending invitation, GrantAlreadyRevoked when neither is present. A NOT_FOUND from either mutation is treated as success, because it means the requested state is already in place.
  • Both operations verify the resulting state and refuse to report a grant or revoke that GitHub did not apply.

What C1 shows for each state:

C1 has no pending state for a grant — it either exists or it does not — so an invitation and an accepted owner map onto the same grant:

State in GitHub What C1 shows
Invited, not accepted yet Owner grant
Invitation accepted, active owner Owner grant, same grant ID
Invitation cancelled or lapsed Grant disappears on the next sync
Never invited No grant

The grant ID being stable across the second row matters: if it changed on acceptance, C1 would read the transition as a revoke followed by a new grant and would corrupt the history exactly where it is most useful. Nothing tracks an expiry — GitHub stops resolving an invitation once it is accepted, cancelled or expired, so it simply stops being emitted.

Every row was exercised against a live GitHub Enterprise Cloud account with the app installed on both levels, driven end to end through a full ConductorOne stack: granting to an org member created the invitation and C1 kept the grant across the following sync, a teammate accepting it turned them into an active owner under the same grant ID, and revoking cleared each state through its own mutation. Also covered live: re-granting while an invitation is pending returns GrantAlreadyExists without sending a second invitation, revoking with nothing to revoke reports success rather than an error, and revoking an active owner leaves their enterprise membership intact.

Auth:

Enterprise Owner provisioning is opt-in: --enable-enterprise-owner-provisioning, off by default. While it is off the connector behaves exactly as it did before this change, so upgrading cannot break an existing deployment. Turning it on requires GitHub App authentication with the app installed on both the enterprise account and the organization, and the Enterprise → People: Read and write permission.

Once enabled, a missing enterprise installation fails the sync rather than emitting no owners. That is deliberate: C1 deletes every resource of a type that a completed sync did not report, so finishing the sync while reading nothing would silently drop the Owner role and every grant on it — and GitHub answers 404 for an uninstalled app, a revoked permission and a slug typo alike, so the connector cannot tell them apart. Failing keeps the sync from completing, so nothing is deleted. The flag is what confines that failure to operators who asked for the capability.

Only one enterprise can be served per connector under App authentication, because owners are read through the single configured organization and an organization belongs to exactly one enterprise. A configuration naming several is rejected with an explanatory error. The PAT path still accepts a list.

Architecture highlights:

  • Pending invitations are not enumerable. Enterprise.ownerInfo.pendingAdminInvitations is the only connection GitHub offers and it is null for installation tokens, so the sync resolves invitations by asking about the enterprise members, aliasing up to 100 logins into one request — measured at a single rate-limit point. An invitation addressed to somebody outside the enterprise is therefore invisible to the sync; invitations created from C1 are always visible, because C1 grants to a user it has already synced.
  • Grants() walks owners and invitations as two phases of one page token via pagination.Bag.
  • A GraphQL transport classifies the errors GitHub returns alongside an HTTP 200, so a rate limit reaches the SDK as a retryable Unavailable. It is layered only on the enterprise clients: the shared GraphQL client is untouched because user.go detects enterprise SAML by matching that error's text. The aliased batch deliberately bypasses it, since it always carries NOT_FOUND entries, and filters those out before classifying the rest — leaving them in would let them claim the code for the whole response, and NOT_FOUND is the one code the SDK downgrades to a warning.
  • customclient now resolves URLs against the go-github client's BaseURL and escapes each path segment, so these endpoints follow --instance-url instead of hardcoding api.github.com.
  • The GraphQL endpoint derivation that existed in three places is now one helper.
  • The published capability set is now complete. The capabilities command runs in CI without credentials, so a connector built from real config omitted every resource type its configuration did not switch on — enterprise roles and licenses need --enterprises, API keys need --sync-secrets, the usage app and its event feed need --sync-last-activity. A DefaultCapabilitiesBuilder registered for that command alone (the pattern baton-aws uses) restores them, which is what lets the catalog advertise enterprise_role as provisionable at all. This does not weaken the per-deployment gating described above: MakeGRPCServerCommand never receives the option, and C1 overwrites the capabilities it stores from the live connector on Validate and on every sync, so a PAT deployment still reports the role as sync-only. The distinction is that the catalog describes what the connector can do once configured, while each tenant's record describes what its own deployment does.
  • Not fixed here: the license resource type still cannot sync under GitHub App authentication, because GitHub does not offer the enterprise_administration permission to Apps. Pre-existing and unrelated to this change, but it means that type has to stay disabled when running the App path with enterprises configured.

Useful links:

@linear-code

linear-code Bot commented Sep 22, 2026

Copy link
Copy Markdown

CXH-2123

Comment thread pkg/connector/enterprise_role.go
Comment thread pkg/connector/connector.go Outdated
Comment thread pkg/customclient/client.go
Comment thread pkg/connector/enterprise_role.go
@github-actions

github-actions Bot commented Sep 22, 2026 •

Copy link
Copy Markdown
Contributor
Superseded — see the current review report for commit 8943329e11c5

Connector PR Review: [CXH-2123] - Add provisioning for the Enterprise Owner role - GitHub Connector

Blocking Issues: 0 | Suggestions: 3 | Threads Resolved: 0
Criteria: Criteria status: loaded .claude/skills/ci-review.md from trusted base 1b8c8f878539.
Review mode: full
View review run

Review Summary

When --enable-enterprise-owner-provisioning is set under GitHub App auth, the connector now builds per-enterprise GraphQL clients lazily. With those clients it syncs the built-in Owner role (owners, then pending invitations resolved through one aliased batch, as two phases of one pagination.Bag token) and registers a separate enterpriseRoleProvisioner that adds Grant and Revoke. Grant invites and refuses in-place promotion; Revoke demotes to UNAFFILIATED and cancels the invitation. Both re-read OwnerState to confirm the change landed. PAT and flag-off paths register the read-only syncer plus license as before. I scanned the full diff for security and correctness and re-checked all 19 prior findings against the current code. I applied the repo criteria: provisioning entity sources (principal → login, entitlement resource → enterprise, no ParentResourceId use), idempotency annotations, gRPC codes on provisioning errors (E2/E3), log levels (A), and the breaking-change gate (BP1/BP5). The new behavior is opt-in and off by default, so it is not an ungated breaking change. go.mod/go.sum are unchanged.

Security Issues

None found. The aliased invitation query passes logins only as GraphQL variables, and the customclient path segments are escaped.

Correctness Issues

None found.

Suggestions

  • Prior — still present (confidence: medium) pkg/connector/enterprise_role.go:438-445: Organization.enterpriseOwners and Enterprise.members cover the whole enterprise account, but user only syncs members of the configured org. An owner from another org in the enterprise gets a grant whose principal was never synced. The author chose to document this in docs/docs-info.md:272 rather than filter, so it stays open as a known limitation.
  • Prior — still present (confidence: medium) pkg/config/config.go:461-464: EnterprisesField and enable-enterprise-owner-provisioning now appear in this connector's GitHub App form, but the App setup steps in docs/connector.mdx (~lines 292-317) don't mention either one (D4). The author declined because enterprise setup is documented in the GitHub Enterprise connector. That argument is weaker now that both fields show up in this connector's own form.
  • Prior — still present (confidence: low) pkg/connector/connector.go:314: when consumed-licenses fails under App auth (a guaranteed later license sync failure with the flag off), the connector logs it at Debug, while repo criteria L1 calls for Warn. The Debug level is inherited from main, and the author declined because of a team-level rule against Warn.

Resolved prior findings

  • Provision capability advertised under PAT (2 threads): fixed. The capability now comes from the separate enterpriseRoleProvisioner type (pkg/connector/enterprise_role.go:284-301), which ResourceSyncers registers only when newEnterpriseRoleClients != nil (pkg/connector/connector.go:501-510).
  • appTokenRefresher held the per-RPC ctx: fixed. It now captures connectorCtx (pkg/connector/connector.go:583), which the refresher and newGitHubAppHTTPClient use.
  • Nil BaseHttpClient from uhttp.NewBaseHttpClient: fixed. Both construction sites nil-check it (pkg/connector/connector.go:661-664, pkg/connector/enterprise_administrator_client.go:106-109).
  • OwnerState fell through its page bound and reported "not an owner": fixed. It now returns codes.Internal when it hits the bound (pkg/connector/enterprise_administrator_client.go:620-624).
  • clients() error aborting the whole sync contradicted the code comment: fixed. Failing the sync is now the documented intent, and the comments at pkg/connector/enterprise_role.go:54-57/65-74 and pkg/connector/connector.go:573-578 state it and give the C1 deletion reason.
  • Unbounded installation walk; 404 skip logged at Debug; hard startup failure with two enterprises; memoized empty or permanent results; isPermanentError missing transient errors (outdated threads): obsolete.
    • listEnterpriseInstallations, isPermanentError and enterpriseClientsSet no longer exist.
    • Discovery is now one direct GetEnterpriseInstallation call per enterprise. A 404 becomes an explicit FailedPrecondition, and the multi-enterprise check is lazy and opt-in only (pkg/connector/connector.go:652-677).
    • clients() memoizes only success (pkg/connector/enterprise_role.go:85-95).
  • Stale "documented fallback" comment: fixed at pkg/connector/graphql_transport.go:3487-3490 of the diff; the comment now says Grant refuses a rejected invitation.
  • customclient comment claimed PathEscape blocks ..: fixed. The comment now says escaping covers slashes only (pkg/customclient/client.go endpoint doc).
  • GetEnterpriseInstallation error path did not close the response body: fixed. defer res.Body.Close() now runs before logBody.
Prompt for AI agents
Verify each finding against the current code and only fix it if needed.

## Suggestions

In `pkg/connector/enterprise_role.go`:
- Around line 438-445 (ownerGrants) and 485-495 (pendingInvitationGrants): owners and invitation candidates span the whole enterprise, while the user resource type only syncs members of the configured org, so some grants point at principals the sync never created. Either skip owners whose database ID isn't among the synced org members, or keep the documented limitation in docs/docs-info.md. Don't change behavior silently.

In `pkg/config/config.go`:
- Around line 461-464: the GitHub App field group now includes EnterprisesField and enable-enterprise-owner-provisioning. Add both optional fields to the GitHub App configuration steps in docs/connector.mdx (~lines 292-317), or point to the GitHub Enterprise integration page for them, so the docs match the fields shown in this connector's form.

In `pkg/connector/connector.go`:
- Around line 314: consumed-licenses failing under App auth means the license resource type will fail the sync. Consider logging it at Warn per repo criteria L1, or leave it at Debug if the team logging policy overrides the repo criteria.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No blocking issues found.

mateoHernandez123 and others added 2 commits September 22, 2026 15:36
@mateoHernandez123
mateoHernandez123 force-pushed the mateoHernandez123/github-enterprise-owner-provisioning branch from 8738a07 to 04872b2 Compare September 22, 2026 18:37
Comment thread pkg/connector/connector.go
Comment thread pkg/connector/enterprise_administrator_client.go
Comment thread pkg/customclient/client.go

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blocking issues found — see review comments.

The GitHub App form exposes Enterprises and Enable enterprise owner
provisioning, but the customer-facing setup doc mentioned neither, in the
app permissions, the connector configuration form, or the self-hosted
manifest.

The app creation flow also needed a correction rather than an addition:
it starts under the organization, but an app that has to read and mutate
enterprise administrators must be created under the enterprise account
and installed on both. Following the steps as written produced an app
that could not serve the capability, with nothing to indicate why.

Co-authored-by: Cursor <cursoragent@cursor.com>
Comment thread docs/connector.mdx Outdated
@github-actions

github-actions Bot commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor
Superseded — see the current review report for commit 9858ffa71c08

Connector PR Review: [CXH-2123] - Add provisioning for the Enterprise Owner role - GitHub Connector

Blocking Issues: 0 | Suggestions: 4 | Threads Resolved: 0
Criteria: Criteria status: loaded .claude/skills/ci-review.md from trusted base 1b8c8f878539.
Review mode: incremental since f94e8a6
View review run

Review Summary

The PR adds Enterprise Owner Grant/Revoke and sync under GitHub App auth, gated behind --enable-enterprise-owner-provisioning. The new commit (9858ffa) changes only docs/connector.mdx. It documents creating the app under the enterprise account, the Enterprise → People permission, the second installation on the enterprise, the Enterprises and Enable enterprise owner provisioning fields (single-enterprise rule, fail-closed behavior), and the matching BATON_* env vars. I scanned the full PR diff again for security and correctness and found no new issues. The incremental artifact was complete (not partial). I applied the trusted repo criteria: D1/D4 docs-staleness and BP1/BP3 for the opt-in gate and its docs; L1 for the prior log-level item. There are no go.mod/go.sum changes. The Grant/Revoke code did not change in this commit, so I did not re-audit the provisioning criteria (PR1–PR3) in depth.

Security Issues

None found.

Correctness Issues

None found.

Suggestions

  • New (confidence: high) docs/connector.mdx:213-215: the "install the app on the enterprise account" step comes before Create GitHub App (line 220), when the app doesn't exist yet. It should move after the final Install step.
  • Prior — still present (confidence: medium) docs/connector.mdx:17-24: the Capabilities table still has no row for Enterprise roles (sync, plus opt-in provisioning of Owner under App auth). This leaves D1 stale. The D4 part of that earlier finding is now fixed (see below).
  • Prior — still present (confidence: medium) pkg/connector/enterprise_role.go:438-445: enterprise owners come from the whole enterprise account, but user syncs only members of the configured org, so a grant can reference a principal that was never synced. This is documented as a known limitation in docs/docs-info.md.
  • Prior — still present (confidence: low) pkg/connector/connector.go:314: under App auth, a consumed-licenses failure means the license sync will fail later, yet it is still logged at Debug; L1 calls for Warn. The level is inherited from main, and the author declined to change it.

Resolved prior findings

  • The docs gap for the enable-enterprise-owner-provisioning / Enterprises fields in App setup (pkg/config/config.go:75 thread, and the D4 half of the docs/docs-info.md thread) is fixed. See docs/connector.mdx:161-163, :206-210, :328-332 and :426-431.
  • Provision capability advertised under PAT (2 threads): fixed. The provisioner is registered only when enterprise-role clients exist (pkg/connector/connector.go, newEnterpriseRoleClients != nil).
  • Per-RPC ctx in appTokenRefresher, nil BaseHttpClient, the OwnerState page bound, the clients() sync-abort comment, the stale "documented fallback" comment, the PathEscape/.. comment, and the unclosed body in GetEnterpriseInstallation: fixed in earlier commits. This commit didn't touch them.
  • Unbounded installation walk, 404 skip at Debug, hard startup failure with two enterprises, memoized empty/permanent results, and isPermanentError missing transient errors: obsolete. listEnterpriseInstallations, isPermanentError and enterpriseClientsSet were removed, and discovery is now a single GetEnterpriseInstallation per enterprise.
Prompt for AI agents
Verify each finding against the current code and only fix it if needed.

## Suggestions

In `docs/connector.mdx`:
- Around line 213-215: The "Optional. install the app on the enterprise account" step comes before "Click Create GitHub App", when the app does not exist yet. Move this step after the final "Click Install" step of the org installation (around line 256), and word it as a second installation of the same app on the enterprise account.
- Around line 17-24: Add a Capabilities table row for Enterprise roles. Mark Sync as supported, and mark Provision as supported for the Owner role under GitHub App auth when enable-enterprise-owner-provisioning is on (a footnote is fine).

In `pkg/connector/enterprise_role.go`:
- Around line 438-445: Enterprise owners are read from the whole enterprise account, but users are synced only from the configured org, so grants can reference unsynced principals. Either filter owners to org members, or keep the documented limitation and make sure it is visible in customer-facing docs.

In `pkg/connector/connector.go`:
- Around line 314: The consumed-licenses probe failure under App auth guarantees a later license sync failure. Consider logging it at Warn instead of Debug (repo criteria L1).

@github-actions

github-actions Bot commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor
Superseded — see the current review report for commit 7f940ca7fa8d

Connector PR Review: [CXH-2123] - Add provisioning for the Enterprise Owner role - GitHub Connector

Blocking Issues: 0 | Suggestions: 4 | Threads Resolved: 0
Criteria: Criteria status: loaded .claude/skills/ci-review.md from trusted base 1b8c8f878539.
Review mode: incremental since f94e8a6
View review run

Review Summary

The PR adds Enterprise Owner Grant/Revoke and sync under GitHub App auth, gated behind --enable-enterprise-owner-provisioning. The new commit (9858ffa) changes only docs/connector.mdx. It documents creating the app under the enterprise account, the Enterprise → People permission, the second installation on the enterprise, the Enterprises and Enable enterprise owner provisioning fields (single-enterprise rule, fail-closed behavior), and the matching BATON_* env vars. I scanned the full PR diff again for security and correctness and found no new issues. The incremental artifact was complete (not partial). I applied the trusted repo criteria: D1/D4 docs-staleness and BP1/BP3 for the opt-in gate and its docs; L1 for the prior log-level item. There are no go.mod/go.sum changes. The Grant/Revoke code did not change in this commit, so I did not re-audit the provisioning criteria (PR1–PR3) in depth.

Security Issues

None found.

Correctness Issues

None found.

Suggestions

  • New (confidence: high) docs/connector.mdx:213-215: the "install the app on the enterprise account" step comes before Create GitHub App (line 220), when the app doesn't exist yet. It should move after the final Install step.
  • Prior — still present (confidence: medium) docs/connector.mdx:17-24: the Capabilities table still has no row for Enterprise roles (sync, plus opt-in provisioning of Owner under App auth). This leaves D1 stale. The D4 part of that earlier finding is now fixed (see below).
  • Prior — still present (confidence: medium) pkg/connector/enterprise_role.go:438-445: enterprise owners come from the whole enterprise account, but user syncs only members of the configured org, so a grant can reference a principal that was never synced. This is documented as a known limitation in docs/docs-info.md.
  • Prior — still present (confidence: low) pkg/connector/connector.go:314: under App auth, a consumed-licenses failure means the license sync will fail later, yet it is still logged at Debug; L1 calls for Warn. The level is inherited from main, and the author declined to change it.

Resolved prior findings

  • The docs gap for the enable-enterprise-owner-provisioning / Enterprises fields in App setup (pkg/config/config.go:75 thread, and the D4 half of the docs/docs-info.md thread) is fixed. See docs/connector.mdx:161-163, :206-210, :328-332 and :426-431.
  • Provision capability advertised under PAT (2 threads): fixed. The provisioner is registered only when enterprise-role clients exist (pkg/connector/connector.go, newEnterpriseRoleClients != nil).
  • Per-RPC ctx in appTokenRefresher, nil BaseHttpClient, the OwnerState page bound, the clients() sync-abort comment, the stale "documented fallback" comment, the PathEscape/.. comment, and the unclosed body in GetEnterpriseInstallation: fixed in earlier commits. This commit didn't touch them.
  • Unbounded installation walk, 404 skip at Debug, hard startup failure with two enterprises, memoized empty/permanent results, and isPermanentError missing transient errors: obsolete. listEnterpriseInstallations, isPermanentError and enterpriseClientsSet were removed, and discovery is now a single GetEnterpriseInstallation per enterprise.
Prompt for AI agents
Verify each finding against the current code and only fix it if needed.

## Suggestions

In `docs/connector.mdx`:
- Around line 213-215: The "Optional. install the app on the enterprise account" step comes before "Click Create GitHub App", when the app does not exist yet. Move this step after the final "Click Install" step of the org installation (around line 256), and word it as a second installation of the same app on the enterprise account.
- Around line 17-24: Add a Capabilities table row for Enterprise roles. Mark Sync as supported, and mark Provision as supported for the Owner role under GitHub App auth when enable-enterprise-owner-provisioning is on (a footnote is fine).

In `pkg/connector/enterprise_role.go`:
- Around line 438-445: Enterprise owners are read from the whole enterprise account, but users are synced only from the configured org, so grants can reference unsynced principals. Either filter owners to org members, or keep the documented limitation and make sure it is visible in customer-facing docs.

In `pkg/connector/connector.go`:
- Around line 314: The consumed-licenses probe failure under App auth guarantees a later license sync failure. Consider logging it at Warn instead of Debug (repo criteria L1).

Reviewed commit: 9858ffa71c08

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No blocking issues found — see the full review report

…se roles

The enterprise-account install step landed between the permissions and
Create GitHub App, telling the reader to install an app that does not
exist yet. Move it after the organization install.

Add the Enterprise roles row to the capabilities table, which still
described the connector as it was before this change.

Co-authored-by: Cursor <cursoragent@cursor.com>
@github-actions

github-actions Bot commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor
Superseded — see the current review report for commit 7f940ca7fa8d

Connector PR Review: [CXH-2123] - Add provisioning for the Enterprise Owner role - GitHub Connector

Blocking Issues: 0 | Suggestions: 2 | Threads Resolved: 0
Criteria: Criteria status: loaded .claude/skills/ci-review.md from trusted base 1b8c8f878539.
Review mode: incremental since 9858ffa
View review run

Review Summary

The new commit only changes docs in docs/connector.mdx:

  • It adds an Enterprise roles row (Sync + Provision) to the Capabilities table.
  • It adds a note that enterprise roles are opt-in and lists what each part needs.
  • It moves the optional "install the app on the enterprise account" step so it now follows the final Install step.

The Go code hasn't changed since the last review. I scanned the full PR diff (all 24 files) again for security and correctness issues, including enterprise discovery, the GraphQL transport, and the customclient paths, and found nothing new.

I applied the repo-local criteria. The Log-level rule (L1) still applies to the inherited Debug log. The Documentation Staleness rules (D1/D4) are now satisfied. The Provisioning, Span, JSON-type and Breaking-change criteria have nothing new to check, because no code changed.

Security Issues

None found.

Correctness Issues

None found.

Suggestions

  • Prior — still present (confidence: medium) pkg/connector/enterprise_role.go:432-445: ownerGrants emits a grant for every owner of the whole enterprise account. The user resource type only syncs members of the configured org, so an owner from another org in the enterprise produces a grant whose principal was never synced. This is recorded as a known limitation in docs/docs-info.md:272.
  • Prior — still present (confidence: low) pkg/connector/connector.go:314: under App auth with --enterprises set, a consumed-licenses failure means the license sync will fail later. It is still logged at Debug, and L1 calls for Warn. The level comes from main, and the author declined to change it.

Resolved prior findings

  • Fixed in this commit:
    • The enterprise install step came before Create GitHub App. It now follows the final Install step (docs/connector.mdx:253-255).
    • The Capabilities table had no Enterprise roles row (D1). The row and opt-in note are at docs/connector.mdx:25-27.
  • Fixed earlier (docs): docs/connector.mdx was missing the new enable-enterprise-owner-provisioning / Enterprises fields (the pkg/config/config.go:75 and docs/docs-info.md threads). Both are now documented.
  • Fixed earlier (provisioning under PAT): Provision capability was advertised under PAT (2 threads at enterprise_role.go:651). The provisioner is now registered only when gh.newEnterpriseRoleClients != nil (pkg/connector/connector.go:162).
  • Fixed earlier (code):
    • Per-RPC ctx in appTokenRefresher: it now uses connectorCtx (pkg/connector/connector.go:607-613).
    • Nil BaseHttpClient: now guarded (connector.go:575-579, enterprise_administrator_client.go:104-106).
    • OwnerState page bound: it now returns an error at enterpriseMaxPages (enterprise_administrator_client.go:596-623).
    • clients() sync-abort comment: corrected (enterprise_role.go:54-57).
    • PathEscape/.. rationale: corrected (pkg/customclient/client.go:51-53).
    • Unclosed body in GetEnterpriseInstallation: it now defers Close before logBody (client.go:98-101).
  • Obsolete: the stale "documented fallback" comment (the phrase no longer appears in pkg/), the unbounded installation walk, the 404 skip at Debug, the startup failure with two enterprises, memoized empty or permanent results, and isPermanentError missing transient errors. listEnterpriseInstallations, isPermanentError and enterpriseClientsSet were removed. Discovery is now a single GetEnterpriseInstallation per enterprise, and a 404 becomes a FailedPrecondition naming the fix (connector.go:581-594).
Prompt for AI agents
Verify each finding against the current code and only fix it if needed.

## Suggestions

In `pkg/connector/enterprise_role.go`:
- Around line 432-445: ownerGrants emits grants for every owner of the enterprise account, but the user resource type only syncs members of the configured organization, so some grants reference principals that were never synced. Either skip or log (Debug) owners who are not members of the configured org, or widen the user sync behind an opt-in flag; the limitation is currently only documented in docs/docs-info.md.

In `pkg/connector/connector.go`:
- Around line 314: When ListEnterpriseConsumedLicenses fails under GitHub App auth with --enterprises set, the license resource type is guaranteed to fail later in the sync. Log this at Warn instead of Debug so operators see why, per the repo log-level rule L1.

@github-actions

github-actions Bot commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor
Superseded — see the current review report for commit b91d9b75b492

Connector PR Review: [CXH-2123] - Add provisioning for the Enterprise Owner role - GitHub Connector

Blocking Issues: 0 | Suggestions: 2 | Threads Resolved: 0
Criteria: Criteria status: loaded .claude/skills/ci-review.md from trusted base 1b8c8f878539.
Review mode: incremental since 9858ffa
View review run

Review Summary

The new commit only changes docs in docs/connector.mdx:

  • It adds an Enterprise roles row (Sync + Provision) to the Capabilities table.
  • It adds a note that enterprise roles are opt-in and lists what each part needs.
  • It moves the optional "install the app on the enterprise account" step so it now follows the final Install step.

The Go code hasn't changed since the last review. I scanned the full PR diff (all 24 files) again for security and correctness issues, including enterprise discovery, the GraphQL transport, and the customclient paths, and found nothing new.

I applied the repo-local criteria. The Log-level rule (L1) still applies to the inherited Debug log. The Documentation Staleness rules (D1/D4) are now satisfied. The Provisioning, Span, JSON-type and Breaking-change criteria have nothing new to check, because no code changed.

Security Issues

None found.

Correctness Issues

None found.

Suggestions

  • Prior — still present (confidence: medium) pkg/connector/enterprise_role.go:432-445: ownerGrants emits a grant for every owner of the whole enterprise account. The user resource type only syncs members of the configured org, so an owner from another org in the enterprise produces a grant whose principal was never synced. This is recorded as a known limitation in docs/docs-info.md:272.
  • Prior — still present (confidence: low) pkg/connector/connector.go:314: under App auth with --enterprises set, a consumed-licenses failure means the license sync will fail later. It is still logged at Debug, and L1 calls for Warn. The level comes from main, and the author declined to change it.

Resolved prior findings

  • Fixed in this commit:
    • The enterprise install step came before Create GitHub App. It now follows the final Install step (docs/connector.mdx:253-255).
    • The Capabilities table had no Enterprise roles row (D1). The row and opt-in note are at docs/connector.mdx:25-27.
  • Fixed earlier (docs): docs/connector.mdx was missing the new enable-enterprise-owner-provisioning / Enterprises fields (the pkg/config/config.go:75 and docs/docs-info.md threads). Both are now documented.
  • Fixed earlier (provisioning under PAT): Provision capability was advertised under PAT (2 threads at enterprise_role.go:651). The provisioner is now registered only when gh.newEnterpriseRoleClients != nil (pkg/connector/connector.go:162).
  • Fixed earlier (code):
    • Per-RPC ctx in appTokenRefresher: it now uses connectorCtx (pkg/connector/connector.go:607-613).
    • Nil BaseHttpClient: now guarded (connector.go:575-579, enterprise_administrator_client.go:104-106).
    • OwnerState page bound: it now returns an error at enterpriseMaxPages (enterprise_administrator_client.go:596-623).
    • clients() sync-abort comment: corrected (enterprise_role.go:54-57).
    • PathEscape/.. rationale: corrected (pkg/customclient/client.go:51-53).
    • Unclosed body in GetEnterpriseInstallation: it now defers Close before logBody (client.go:98-101).
  • Obsolete: the stale "documented fallback" comment (the phrase no longer appears in pkg/), the unbounded installation walk, the 404 skip at Debug, the startup failure with two enterprises, memoized empty or permanent results, and isPermanentError missing transient errors. listEnterpriseInstallations, isPermanentError and enterpriseClientsSet were removed. Discovery is now a single GetEnterpriseInstallation per enterprise, and a 404 becomes a FailedPrecondition naming the fix (connector.go:581-594).
Prompt for AI agents
Verify each finding against the current code and only fix it if needed.

## Suggestions

In `pkg/connector/enterprise_role.go`:
- Around line 432-445: ownerGrants emits grants for every owner of the enterprise account, but the user resource type only syncs members of the configured organization, so some grants reference principals that were never synced. Either skip or log (Debug) owners who are not members of the configured org, or widen the user sync behind an opt-in flag; the limitation is currently only documented in docs/docs-info.md.

In `pkg/connector/connector.go`:
- Around line 314: When ListEnterpriseConsumedLicenses fails under GitHub App auth with --enterprises set, the license resource type is guaranteed to fail later in the sync. Log this at Warn instead of Debug so operators see why, per the repo log-level rule L1.

Reviewed commit: 7f940ca7fa8d

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No blocking issues found — see the full review report

@luisina-santos luisina-santos left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would like to revisit this connector and baton-github-enterprise too. if it is an enterprise only feature, should we add it there directly? it is actually an enterprise only feature?

Comment thread .github/workflows/capabilities_and_config.yaml Outdated
Comment thread docs/connector.mdx
| Orgs | <Icon icon="square-check" iconType="solid" color="#c937ae"/> | <Icon icon="square-check" iconType="solid" color="#c937ae"/> |
| GitHub Apps (NHI) | <Icon icon="square-check" iconType="solid" color="#c937ae"/> | |
| Secrets - API keys | <Icon icon="square-check" iconType="solid" color="#c937ae"/> | |
| Enterprise roles | <Icon icon="square-check" iconType="solid" color="#c937ae"/> | <Icon icon="square-check" iconType="solid" color="#c937ae"/> |

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is a role valid JUST for github enterprise? if so, it should not be documented here

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is GitHub Enterprise Cloud, which is a different product from the GitHub Enterprise integration: Enterprise Cloud is accessed at github.com, so this page is its home. The /baton/github-enterprise page says so itself ("If you access GitHub at github.com, go to the GitHub integration"), and that connector marks instance-url as required, so an Enterprise Cloud customer on github.com cannot use it.

It also is not new here: enterprises is already a top-level field on main and enterprise_role already syncs when it is set (connector.go:157-162 on main). The feature was validated end to end against a real Enterprise Cloud enterprise through this connector with no instance-url set.

That said the naming collision is real and the row as written invited exactly this question, so in b91d9b7 I reworded it to name Enterprise Cloud explicitly and point at the other integration for custom domains.

Comment thread pkg/config/config.go
// Off by default because it needs setup nobody has done yet: turning it on
// without the enterprise installation fails the sync, which is only a fair
// trade for someone who asked for the capability.
enableEnterpriseOwnerProvisioning = field.BoolField(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is a failure produced because of enterprise needed? we should not expose enterprise owner role in regular github connector if it is limited JUST for enterprise apps

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as the docs thread: GitHub Enterprise Cloud enterprise accounts live at github.com, so this is the connector for them — baton-github-enterprise requires instance-url and targets custom domains.

On the failure: it is about the enterprise-level app installation, not the product. With the flag on, the connector fails the sync when it cannot reach the enterprise, because C1 deletes every resource of a type a completed sync did not report; finishing while reading no owners would silently drop the Owner role and every grant on it, and GitHub answers 404 for an uninstalled app, a revoked permission and a slug typo alike. The flag exists so that failure is only reachable by someone who asked for the capability.

In b91d9b7 and 8b5a601 the field descriptions now name Enterprise Cloud and state the consequence, so the same ambiguity does not reach a C1 admin.

@sergiocorral-conductorone sergiocorral-conductorone left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

automated review — Round 2

Comment thread pkg/config/config.go
Comment thread pkg/connector/default_capabilities_test.go Outdated
…ses, and correct the enterprise docs

Enterprises reached the GitHub App field group but not the personal
access token one, so a hosted token deployment could not configure the
capability at all -- and the token path is the one that syncs every
enterprise role without the opt-in. The sibling baton-github-enterprise
already lists the field in both groups.

Both field descriptions now name GitHub Enterprise Cloud, which is
accessed at github.com and therefore belongs to this connector rather
than to the separate GitHub Enterprise integration, and they refer to
the settings by the names the ConductorOne form shows instead of by
flag.

The documentation had three errors and one gap. The README described
the license type as unregistered under App authentication when it stays
registered and its 403 deliberately fails the sync, presented the
opt-in as provisioning-only when it also gates syncing, and omitted the
enterprise permission the whole capability rests on. docs-info claimed
GitHub calls organization roles "enterprise licenses", which it does
not, and its monorepo references read as paths in this repo. The setup
page never mentioned the field on the token path.

Also records that the consumed-licenses endpoint is absent from GitHub
Enterprise Server, so that resource type is unusable there for either
credential -- an open question for the wrapper rather than something
this package can diagnose.

Removes capabilities_and_config.yaml per review. The metadata is now
regenerated by hand until baton-admin enables the managed workflow,
which docs-info states.

The default capabilities guard now also asserts capability parity, so
swapping the provisioning syncer for the read-only one fails the test
rather than silently dropping CAPABILITY_PROVISION.

Co-authored-by: Cursor <cursoragent@cursor.com>
@github-actions

github-actions Bot commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor
Superseded — see the current review report for commit b91d9b75b492

Connector PR Review: [CXH-2123] - Add provisioning for the Enterprise Owner role - GitHub Connector

Blocking Issues: 0 | Suggestions: 3 | Threads Resolved: 0
Criteria: Criteria status: loaded .claude/skills/ci-review.md from trusted base 1b8c8f878539.
Review mode: incremental since 7f940ca
View review run

Review Summary

The new commits change docs and config only, plus one test:

  • Descriptions: the enterprises and enable-enterprise-owner-provisioning descriptions are clearer, and EnterprisesField is added to the PAT field group (pkg/config/config.go:153). This is additive only, since PAT already read that field. config_schema.json was regenerated to match.
  • Workflow: capabilities_and_config.yaml, which this PR had added earlier, is removed again. It does not exist on base, so nothing changes relative to main.
  • Docs: README.md, docs/connector.mdx and docs/docs-info.md now cover PAT enterprise setup, Enterprise Cloud versus GHES, and the published-capabilities rationale.
  • Test: default_capabilities_test.go now also checks that DefaultCapabilitiesBuilder registers a provisioning syncer wherever a real deployment does.

I scanned the full PR diff (22 files) for security and correctness, and re-checked every prior finding against the current code. I applied the repo-local criteria: log level (L1), error codes (E2), provisioning entity sources (PR1–PR3), breaking-change gating (BP1/BP5: the capability is opt-in and off by default), and docs staleness (D1–D4). None of them is violated by the new commits. The incremental diff was complete: no dropped paths, not truncated.

Security Issues

None found.

Correctness Issues

None found.

Suggestions

  • New (confidence: medium) pkg/config/config.go:29-33: the Enterprises description says that under a GitHub App it "does nothing on its own". In fact, with the flag off, LicenseBuilder stays registered (pkg/connector/connector.go:182-184) and its 403 fails the sync. The docs say this; the UI text does not.
  • Prior — still present (confidence: medium) pkg/connector/enterprise_role.go:427-448: ownerGrants emits a grant for every owner of the enterprise account, including owners outside the configured org whose user resource was never synced. It is recorded as a known limitation in docs/docs-info.md.
  • Prior — still present (confidence: low) pkg/connector/connector.go:314: the consumed-licenses failure under App auth is still logged at Debug, and L1 calls for Warn. The level comes from main.

Resolved prior findings

  • Fixed (docs): docs/connector.mdx staleness, found in the docs/docs-info.md:1 and pkg/config/config.go:79 threads. The Capabilities table has an Enterprise roles row with an opt-in note (docs/connector.mdx:25-29), and both fields are documented in the PAT and App setup steps.
  • Fixed (provision capability under PAT): found in 2 threads at enterprise_role.go:651. The provisioning syncer is now registered only when gh.newEnterpriseRoleClients != nil (pkg/connector/connector.go:162-170).
  • Fixed (per-RPC ctx): appTokenRefresher now uses connectorCtx (connector.go:607-613).
  • Fixed (nil BaseHttpClient): now guarded (connector.go:575-579).
  • Fixed (OwnerState page bound): it returns Internal when it hits enterpriseMaxPages (enterprise_administrator_client.go:618-622).
  • Fixed (clients() sync-abort comment): the comment now says a build error deliberately fails the sync (enterprise_role.go:54-57).
  • Fixed (PathEscape/.. rationale): corrected (pkg/customclient/client.go:51-53).
  • Fixed (unclosed body): GetEnterpriseInstallation now defers Close before logBody (client.go:95-98).
  • Obsolete:
    • Removed code: the stale "documented fallback" comment, the unbounded installation walk, the 404 skip at Debug, the startup failure with two enterprises, the memoized empty/permanent results, and the isPermanentError gap. None of that code exists in pkg/ any more.
    • What replaced it: discovery is a single GetEnterpriseInstallation per enterprise. A 404 becomes a FailedPrecondition naming the fix (connector.go:581-594), and more than one enterprise is rejected at client build (connector.go:568-573).
Prompt for AI agents
Verify each finding against the current code and only fix it if needed.

## Suggestions

In `pkg/config/config.go`:
- Around line 29-33: The Enterprises field description says that with a GitHub App the setting "does nothing on its own". With App auth, --enterprises set and --enable-enterprise-owner-provisioning off, ResourceSyncers still registers LicenseBuilder (pkg/connector/connector.go:182-184), and its 403 fails the sync. Reword the description to say that under a GitHub App it syncs no roles and the license resource type fails the sync unless it is paired with "Enable enterprise owner provisioning". Then regenerate config_schema.json.

In `pkg/connector/enterprise_role.go`:
- Around line 427-448: ownerGrants emits a grant for every enterprise-account owner, including users outside the configured org whose user resource is never synced. Consider filtering owners to known org members, or emitting those principals, if dangling grants are a problem. It is currently documented as a known limitation.

In `pkg/connector/connector.go`:
- Around line 314: Under App auth with --enterprises set, the consumed-licenses failure means the license sync will fail later. Log it at Warn instead of Debug, per the L1 log-level rule.

Comment thread pkg/config/config.go Outdated
@github-actions

github-actions Bot commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor
Superseded — see the current review report for commit 8b5a6019cd2a

Connector PR Review: [CXH-2123] - Add provisioning for the Enterprise Owner role - GitHub Connector

Blocking Issues: 0 | Suggestions: 3 | Threads Resolved: 0
Criteria: Criteria status: loaded .claude/skills/ci-review.md from trusted base 1b8c8f878539.
Review mode: incremental since 7f940ca
View review run

Review Summary

The new commits change docs and config only, plus one test:

  • Descriptions: the enterprises and enable-enterprise-owner-provisioning descriptions are clearer, and EnterprisesField is added to the PAT field group (pkg/config/config.go:153). This is additive only, since PAT already read that field. config_schema.json was regenerated to match.
  • Workflow: capabilities_and_config.yaml, which this PR had added earlier, is removed again. It does not exist on base, so nothing changes relative to main.
  • Docs: README.md, docs/connector.mdx and docs/docs-info.md now cover PAT enterprise setup, Enterprise Cloud versus GHES, and the published-capabilities rationale.
  • Test: default_capabilities_test.go now also checks that DefaultCapabilitiesBuilder registers a provisioning syncer wherever a real deployment does.

I scanned the full PR diff (22 files) for security and correctness, and re-checked every prior finding against the current code. I applied the repo-local criteria: log level (L1), error codes (E2), provisioning entity sources (PR1–PR3), breaking-change gating (BP1/BP5: the capability is opt-in and off by default), and docs staleness (D1–D4). None of them is violated by the new commits. The incremental diff was complete: no dropped paths, not truncated.

Security Issues

None found.

Correctness Issues

None found.

Suggestions

  • New (confidence: medium) pkg/config/config.go:29-33: the Enterprises description says that under a GitHub App it "does nothing on its own". In fact, with the flag off, LicenseBuilder stays registered (pkg/connector/connector.go:182-184) and its 403 fails the sync. The docs say this; the UI text does not.
  • Prior — still present (confidence: medium) pkg/connector/enterprise_role.go:427-448: ownerGrants emits a grant for every owner of the enterprise account, including owners outside the configured org whose user resource was never synced. It is recorded as a known limitation in docs/docs-info.md.
  • Prior — still present (confidence: low) pkg/connector/connector.go:314: the consumed-licenses failure under App auth is still logged at Debug, and L1 calls for Warn. The level comes from main.

Resolved prior findings

  • Fixed (docs): docs/connector.mdx staleness, found in the docs/docs-info.md:1 and pkg/config/config.go:79 threads. The Capabilities table has an Enterprise roles row with an opt-in note (docs/connector.mdx:25-29), and both fields are documented in the PAT and App setup steps.
  • Fixed (provision capability under PAT): found in 2 threads at enterprise_role.go:651. The provisioning syncer is now registered only when gh.newEnterpriseRoleClients != nil (pkg/connector/connector.go:162-170).
  • Fixed (per-RPC ctx): appTokenRefresher now uses connectorCtx (connector.go:607-613).
  • Fixed (nil BaseHttpClient): now guarded (connector.go:575-579).
  • Fixed (OwnerState page bound): it returns Internal when it hits enterpriseMaxPages (enterprise_administrator_client.go:618-622).
  • Fixed (clients() sync-abort comment): the comment now says a build error deliberately fails the sync (enterprise_role.go:54-57).
  • Fixed (PathEscape/.. rationale): corrected (pkg/customclient/client.go:51-53).
  • Fixed (unclosed body): GetEnterpriseInstallation now defers Close before logBody (client.go:95-98).
  • Obsolete:
    • Removed code: the stale "documented fallback" comment, the unbounded installation walk, the 404 skip at Debug, the startup failure with two enterprises, the memoized empty/permanent results, and the isPermanentError gap. None of that code exists in pkg/ any more.
    • What replaced it: discovery is a single GetEnterpriseInstallation per enterprise. A 404 becomes a FailedPrecondition naming the fix (connector.go:581-594), and more than one enterprise is rejected at client build (connector.go:568-573).
Prompt for AI agents
Verify each finding against the current code and only fix it if needed.

## Suggestions

In `pkg/config/config.go`:
- Around line 29-33: The Enterprises field description says that with a GitHub App the setting "does nothing on its own". With App auth, --enterprises set and --enable-enterprise-owner-provisioning off, ResourceSyncers still registers LicenseBuilder (pkg/connector/connector.go:182-184), and its 403 fails the sync. Reword the description to say that under a GitHub App it syncs no roles and the license resource type fails the sync unless it is paired with "Enable enterprise owner provisioning". Then regenerate config_schema.json.

In `pkg/connector/enterprise_role.go`:
- Around line 427-448: ownerGrants emits a grant for every enterprise-account owner, including users outside the configured org whose user resource is never synced. Consider filtering owners to known org members, or emitting those principals, if dangling grants are a problem. It is currently documented as a known limitation.

In `pkg/connector/connector.go`:
- Around line 314: Under App auth with --enterprises set, the consumed-licenses failure means the license sync will fail later. Log it at Warn instead of Debug, per the L1 log-level rule.

Reviewed commit: b91d9b75b492

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No blocking issues found — see the full review report

…under app auth

The field description said the setting does nothing on its own under a
GitHub App. It does something worse: the license resource type stays
registered and its 403 fails the whole sync. That description is one of
the places an operator is expected to learn this before configuring the
connector, so it has to state the consequence rather than understate it.

Co-authored-by: Cursor <cursoragent@cursor.com>
@github-actions

github-actions Bot commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor
Superseded — see the current review report for commit 8b5a6019cd2a

Connector PR Review: [CXH-2123] - Add provisioning for the Enterprise Owner role - GitHub Connector

Blocking Issues: 0 | Suggestions: 3 | Threads Resolved: 0
Criteria: Criteria status: loaded .claude/skills/ci-review.md from trusted base 1b8c8f878539.
Review mode: incremental since b91d9b7
View review run

Review Summary

The new commit (8b5a601) only rewrites the enterprises field description in pkg/config/config.go:27-33, config_schema.json and README.md. It now says that under a GitHub App the field doesn't work on its own: no roles are returned and the license resource type fails the sync. That matches pkg/connector/connector.go:182-184. No Go logic changed. The incremental artifact was complete; nothing was dropped or truncated.

I also re-scanned the full PR diff for security and correctness. That includes the provisioning paths, the client build and installation discovery (connector.go:560-620), the owner walk bound (enterprise_administrator_client.go:605-630), customclient URL building and body handling, and a grep for secret logging, TLS bypass and entity-source misuse. No new security or correctness issues turned up.

I applied the repo-local criteria:

  • A (log levels): the Debug at connector.go:314 is still present, see Suggestions.
  • B (error codes): FailedPrecondition and Internal are used appropriately.
  • E (breaking-change gate): the feature is opt-in behind --enable-enterprise-owner-provisioning, so BP5 applies.
  • F (provisioning): no entitlement.Resource.ParentResourceId use in the new enterprise Grant/Revoke.
  • C and D (spans, JSON types): nothing relevant in this delta.

Coverage note: the full-diff pass leaned on the previous reviews' line-level coverage of the unchanged Go code. This run re-read the hotspots listed above, not all 4.4k lines line by line.

Security Issues

None found.

Correctness Issues

None found.

Suggestions

  • New (confidence: medium) .github/workflows/capabilities_and_config.yaml: the PR deletes this workflow, but it does exist on main (blob 55d9d19d, from [OPS-1301] Use baton-ci app token in capabilities_and_config.yaml #147), so the earlier summary was wrong to say it didn't. It is the only job that regenerates config_schema.json and baton_capabilities.json on push to main. The shared verify.yaml@v4 only consumes the committed files and release.yaml@v4 doesn't generate them, so both will drift after merge unless something else replaces this job.
  • Prior — still present (confidence: medium) pkg/connector/enterprise_role.go:427-448: ownerGrants emits a grant for every owner of the enterprise account, including owners outside the configured org whose user resource was never synced. docs/docs-info.md documents this as a known limitation.
  • Prior — still present (confidence: low) pkg/connector/connector.go:314: under App auth the consumed-licenses failure is logged at Debug, but L1 calls for Warn. The level comes from main.

Resolved prior findings

  • Fixed: the Enterprises description claimed the field "does nothing on its own" under a GitHub App. It now states that the license type fails the sync (pkg/config/config.go:29-33, mirrored in config_schema.json and README.md).
  • Fixed: docs/connector.mdx staleness (the docs/docs-info.md:1 and config.go:79 threads) is resolved by the Enterprise roles row and the setup docs.
  • Fixed: the provision capability under PAT (2 threads) is gated on gh.newEnterpriseRoleClients != nil (connector.go:162-170).
  • Fixed:
    • The per-RPC ctx: appTokenRefresher now uses connectorCtx (connector.go:607-613).
    • The nil BaseHttpClient is now guarded (connector.go:575-579).
    • The OwnerState page bound now returns Internal (enterprise_administrator_client.go:618-622).
    • The "sync-abort" comment is corrected (enterprise_role.go:54-57); failing the sync is now intentional and documented.
    • The PathEscape rationale is fixed (customclient/client.go:51-53).
    • The unclosed error body is closed (customclient/client.go:95-98).
  • Obsolete: the unbounded installation walk, the 404 skip at Debug, the startup failure with two enterprises, both memoization threads, the "documented fallback" comment and the helpers.go gRPC-status gap. That code is gone. It was replaced by a single GetEnterpriseInstallation call per enterprise, where a 404 becomes FailedPrecondition (connector.go:581-594), and by the multi-enterprise rejection at client build (connector.go:568-573).
Prompt for AI agents
Verify each finding against the current code and only fix it if needed.

## Suggestions

In `.github/workflows/capabilities_and_config.yaml`:
- Whole file (deleted): this PR deletes a workflow that exists on main. It is the only job that
  regenerates config_schema.json and baton_capabilities.json on push to main. Restore the file,
  or if removal is intended, document it in the PR description and say what regenerates those
  files (the shared verify.yaml@v4 only reads them and release.yaml@v4 does not generate them).

In `pkg/connector/enterprise_role.go`:
- Around line 427-448: ownerGrants emits grants for every enterprise-account owner, including
  users outside the configured org whose user resources are never synced. Either skip
  principals not present in the org membership or keep the documented limitation.

In `pkg/connector/connector.go`:
- Around line 314: raise the consumed-licenses failure log under App auth from Debug to Warn,
  since it is an upstream 403 caused by customer configuration (criteria L1).

Comment thread .github/workflows/capabilities_and_config.yaml
@github-actions

github-actions Bot commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor
Superseded — see the current review report for commit 414af6af43db

Connector PR Review: [CXH-2123] - Add provisioning for the Enterprise Owner role - GitHub Connector

Blocking Issues: 0 | Suggestions: 3 | Threads Resolved: 0
Criteria: Criteria status: loaded .claude/skills/ci-review.md from trusted base 1b8c8f878539.
Review mode: incremental since b91d9b7
View review run

Review Summary

The new commit (8b5a601) only rewrites the enterprises field description in pkg/config/config.go:27-33, config_schema.json and README.md. It now says that under a GitHub App the field doesn't work on its own: no roles are returned and the license resource type fails the sync. That matches pkg/connector/connector.go:182-184. No Go logic changed. The incremental artifact was complete; nothing was dropped or truncated.

I also re-scanned the full PR diff for security and correctness. That includes the provisioning paths, the client build and installation discovery (connector.go:560-620), the owner walk bound (enterprise_administrator_client.go:605-630), customclient URL building and body handling, and a grep for secret logging, TLS bypass and entity-source misuse. No new security or correctness issues turned up.

I applied the repo-local criteria:

  • A (log levels): the Debug at connector.go:314 is still present, see Suggestions.
  • B (error codes): FailedPrecondition and Internal are used appropriately.
  • E (breaking-change gate): the feature is opt-in behind --enable-enterprise-owner-provisioning, so BP5 applies.
  • F (provisioning): no entitlement.Resource.ParentResourceId use in the new enterprise Grant/Revoke.
  • C and D (spans, JSON types): nothing relevant in this delta.

Coverage note: the full-diff pass leaned on the previous reviews' line-level coverage of the unchanged Go code. This run re-read the hotspots listed above, not all 4.4k lines line by line.

Security Issues

None found.

Correctness Issues

None found.

Suggestions

  • New (confidence: medium) .github/workflows/capabilities_and_config.yaml: the PR deletes this workflow, but it does exist on main (blob 55d9d19d, from [OPS-1301] Use baton-ci app token in capabilities_and_config.yaml #147), so the earlier summary was wrong to say it didn't. It is the only job that regenerates config_schema.json and baton_capabilities.json on push to main. The shared verify.yaml@v4 only consumes the committed files and release.yaml@v4 doesn't generate them, so both will drift after merge unless something else replaces this job.
  • Prior — still present (confidence: medium) pkg/connector/enterprise_role.go:427-448: ownerGrants emits a grant for every owner of the enterprise account, including owners outside the configured org whose user resource was never synced. docs/docs-info.md documents this as a known limitation.
  • Prior — still present (confidence: low) pkg/connector/connector.go:314: under App auth the consumed-licenses failure is logged at Debug, but L1 calls for Warn. The level comes from main.

Resolved prior findings

  • Fixed: the Enterprises description claimed the field "does nothing on its own" under a GitHub App. It now states that the license type fails the sync (pkg/config/config.go:29-33, mirrored in config_schema.json and README.md).
  • Fixed: docs/connector.mdx staleness (the docs/docs-info.md:1 and config.go:79 threads) is resolved by the Enterprise roles row and the setup docs.
  • Fixed: the provision capability under PAT (2 threads) is gated on gh.newEnterpriseRoleClients != nil (connector.go:162-170).
  • Fixed:
    • The per-RPC ctx: appTokenRefresher now uses connectorCtx (connector.go:607-613).
    • The nil BaseHttpClient is now guarded (connector.go:575-579).
    • The OwnerState page bound now returns Internal (enterprise_administrator_client.go:618-622).
    • The "sync-abort" comment is corrected (enterprise_role.go:54-57); failing the sync is now intentional and documented.
    • The PathEscape rationale is fixed (customclient/client.go:51-53).
    • The unclosed error body is closed (customclient/client.go:95-98).
  • Obsolete: the unbounded installation walk, the 404 skip at Debug, the startup failure with two enterprises, both memoization threads, the "documented fallback" comment and the helpers.go gRPC-status gap. That code is gone. It was replaced by a single GetEnterpriseInstallation call per enterprise, where a 404 becomes FailedPrecondition (connector.go:581-594), and by the multi-enterprise rejection at client build (connector.go:568-573).
Prompt for AI agents
Verify each finding against the current code and only fix it if needed.

## Suggestions

In `.github/workflows/capabilities_and_config.yaml`:
- Whole file (deleted): this PR deletes a workflow that exists on main. It is the only job that
  regenerates config_schema.json and baton_capabilities.json on push to main. Restore the file,
  or if removal is intended, document it in the PR description and say what regenerates those
  files (the shared verify.yaml@v4 only reads them and release.yaml@v4 does not generate them).

In `pkg/connector/enterprise_role.go`:
- Around line 427-448: ownerGrants emits grants for every enterprise-account owner, including
  users outside the configured org whose user resources are never synced. Either skip
  principals not present in the org membership or keep the documented limitation.

In `pkg/connector/connector.go`:
- Around line 314: raise the consumed-licenses failure log under App auth from Debug to Warn,
  since it is an upstream 403 caused by customer configuration (criteria L1).

Reviewed commit: 8b5a6019cd2a

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No blocking issues found — see the full review report

Copy link
Copy Markdown
Contributor

Code Review Re-check — Sweep 64 (2026-09-29)

Verdict: CHANGES REQUESTED (unchanged) · HEAD 8b5a6019 · incremental diff from 8943329e

The new commits deliver docs and the DefaultCapabilitiesBuilder wiring. No connector logic changed. All prior findings remain at their sweep-62 status.


B1 — Sync-path NotFound in enterprise_role.go [BLOCKING, never previously posted]

ownerGrants and pendingInvitationGrants both propagate the raw error from client.owners() directly:

owners, err := client.owners(ctx, slug)
if err != nil {
    return nil, nil, err
}

When a GitHub App lacks the Enterprise: Read permission, the GraphQL call returns codes.NotFound. The baton-sdk treats NotFound from a syncer as a warning and silently drops all Owner grants for that enterprise. The operator sees no error; the review reports "success" but Owner grants are gone.

Required fix: detect codes.NotFound on the client.owners() call and return a clear InvalidArgument (misconfiguration) or PermissionDenied error so the sync fails loudly rather than silently. Add a test that covers the NotFound path.


Other open items (not blocking merge, but tracked)

  • m2 — read-then-act race on Grant: re-read OwnerState once before returning FailedPrecondition from Grant to avoid a stale-read false negative.
  • m3 — enterprise installation token: token minted with all permissions; scope to enterprise-specific permissions.
  • New (non-blocking): .github/workflows/capabilities_and_config.yaml deleted — document locally that future contributors must run the generation step manually or add a replacement CI job to avoid baton_capabilities.json drift.

Please address B1 before merging.

…ps resolving

NotFound is the one code the SDK downgrades to a warning: SyncGrantsOp
skips the action and the sync still completes, and C1 deletes the grants
a completed sync did not report. So a NotFound escaping Grants revokes
every Owner silently, which is the failure the rest of this resource
type is built to avoid.

Confirmed against the live API with an installation token. An
unresolvable organization answers HTTP 200 with a GraphQL
errors[{type: NOT_FOUND}], which the enterprise transport maps to
codes.NotFound. An organization the app cannot access answers FORBIDDEN
instead, and the transport already ranks that above NOT_FOUND, so the
permission case fails loudly and is unchanged.

A statically wrong organization never reaches this path -- startup fails
on the REST installation lookup. The reachable case is service mode,
where the clients are memoized once and the organization is renamed or
uninstalled while the process keeps running.

Scoped to the sync path. Revoke still reads NotFound as 'already gone'
for its idempotency, which is why this is not in the shared client.

Co-authored-by: Cursor <cursoragent@cursor.com>
@github-actions

github-actions Bot commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor
Superseded — see the current review report for commit 414af6af43db

Connector PR Review: [CXH-2123] - Add provisioning for the Enterprise Owner role - GitHub Connector

Blocking Issues: 0 | Suggestions: 3 | Threads Resolved: 0
Criteria: Criteria status: loaded .claude/skills/ci-review.md from trusted base 1b8c8f878539.
Review mode: incremental since 8b5a601
View review run

Review Summary

The new commit adds failClosedOnUnreadableEnterprise (pkg/connector/enterprise_role.go:434-443). When the enterprise-owner grant sync gets a NotFound, it now returns FailedPrecondition. The SDK downgrades NotFound to a warning, and a completed sync with no owners would make C1 revoke every Owner grant; this change stops that. The commit also adds a test for it. I checked that the change does not catch expected per-login misses: pendingOwnerInvitations drops per-alias NOT_FOUND entries before classifying errors (enterprise_administrator_client.go:481-491). I also checked that status.Code still sees the code through the %w wrapping in owners/members, since grpc v1.83 unwraps. Revoke's use of NotFound to mean "already gone" (enterprise_role.go:621,626) is unchanged.

I scanned the full PR diff for security and correctness. I applied the trusted criteria as follows:

  • A (log levels): the prior Debug at connector.go:314 is still present.
  • B/E2: the new code correctly uses FailedPrecondition and not Internal, so the sync fails without being retried as a transient error.
  • E (breaking-change gate): the feature is still opt-in, so BP5 applies.
  • F (provisioning): Grant/Revoke did not change in this push.

The incremental artifact was complete (partial: false).

Security Issues

None found.

Correctness Issues

None found.

Suggestions

  • Prior — still present (confidence: medium) .github/workflows/capabilities_and_config.yaml: the PR deletes this workflow, but it still exists on main. It is the only job that regenerates config_schema.json and baton_capabilities.json on push to main. The remaining workflows (ci, verify, release, check-versions, connector-docs, update-dependencies) don't replace it, so the committed artifacts will drift after future config or capability changes.
  • Prior — still present (confidence: medium) pkg/connector/enterprise_role.go:446-466: ownerGrants emits grants for every owner of the enterprise account from Organization.enterpriseOwners. That includes owners outside the configured org whose user resource was never synced. It is documented as a known limitation in docs/docs-info.md.
  • Prior — still present (confidence: low) pkg/connector/connector.go:314: under App auth, the consumed-licenses probe failure is logged at Debug, even though it predicts that the license resource type will fail the sync. L1 suggests Warn. This behavior was inherited from main.

Resolved prior findings

  • Fixed:
    • docs/connector.mdx staleness (the docs-info.md:1 and config.go:79 threads): the docs now include an Enterprise roles row and setup docs.
    • Provision capability advertised under PAT (2 threads): it is now gated on gh.newEnterpriseRoleClients != nil in connector.go.
    • Per-RPC ctx in appTokenRefresher (connector.go:618): it now uses connectorCtx.
    • Nil BaseHttpClient (connector.go:577): it is now guarded.
    • OwnerState page-bound fallthrough (enterprise_administrator_client.go:616): it now returns Internal.
    • The "sync-abort" comment (enterprise_role.go:177): corrected. Failing the sync is now intentional and documented, and this push extends that to NotFound.
    • The PathEscape rationale (customclient/client.go:57): corrected.
    • The unclosed error body (customclient/client.go:100): now closed.
  • Obsolete: the unbounded installation walk, the 404 skip logged at Debug, the startup failure with two enterprises, both memoization threads, the "documented fallback" comment and the helpers.go gRPC-status gap. That code was replaced by a single GetEnterpriseInstallation call per enterprise (a 404 there becomes FailedPrecondition, connector.go:581-594) and by the multi-enterprise rejection at client build.
Prompt for AI agents
Verify each finding against the current code and only fix it if needed.

## Suggestions

In `.github/workflows/capabilities_and_config.yaml`:
- The PR deletes this workflow, which is the only job that regenerates config_schema.json and baton_capabilities.json on push to main. Either restore it or confirm another workflow now generates and commits these artifacts, so they do not drift after future config or capability changes.

In `pkg/connector/enterprise_role.go`:
- Around line 446-466: ownerGrants emits a grant for every enterprise-account owner, including owners outside the configured org whose user resource is never synced. Consider filtering to principals that are org members, or keep the documented limitation in docs/docs-info.md if this is intentional.

In `pkg/connector/connector.go`:
- Around line 314: under GitHub App auth with --enterprises set, the consumed-licenses probe failure is logged at Debug even though it predicts the license resource type will fail the sync. Raise it to Warn so operators see it (criteria L1).

@github-actions

github-actions Bot commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

Connector PR Review: [CXH-2123] - Add provisioning for the Enterprise Owner role - GitHub Connector

Blocking Issues: 0 | Suggestions: 3 | Threads Resolved: 0
Criteria: Criteria status: loaded .claude/skills/ci-review.md from trusted base 1b8c8f878539.
Review mode: incremental since 8b5a601
View review run

Review Summary

The new commit adds failClosedOnUnreadableEnterprise (pkg/connector/enterprise_role.go:434-443). When the enterprise-owner grant sync gets a NotFound, it now returns FailedPrecondition. The SDK downgrades NotFound to a warning, and a completed sync with no owners would make C1 revoke every Owner grant; this change stops that. The commit also adds a test for it. I checked that the change does not catch expected per-login misses: pendingOwnerInvitations drops per-alias NOT_FOUND entries before classifying errors (enterprise_administrator_client.go:481-491). I also checked that status.Code still sees the code through the %w wrapping in owners/members, since grpc v1.83 unwraps. Revoke's use of NotFound to mean "already gone" (enterprise_role.go:621,626) is unchanged.

I scanned the full PR diff for security and correctness. I applied the trusted criteria as follows:

  • A (log levels): the prior Debug at connector.go:314 is still present.
  • B/E2: the new code correctly uses FailedPrecondition and not Internal, so the sync fails without being retried as a transient error.
  • E (breaking-change gate): the feature is still opt-in, so BP5 applies.
  • F (provisioning): Grant/Revoke did not change in this push.

The incremental artifact was complete (partial: false).

Security Issues

None found.

Correctness Issues

None found.

Suggestions

  • Prior — still present (confidence: medium) .github/workflows/capabilities_and_config.yaml: the PR deletes this workflow, but it still exists on main. It is the only job that regenerates config_schema.json and baton_capabilities.json on push to main. The remaining workflows (ci, verify, release, check-versions, connector-docs, update-dependencies) don't replace it, so the committed artifacts will drift after future config or capability changes.
  • Prior — still present (confidence: medium) pkg/connector/enterprise_role.go:446-466: ownerGrants emits grants for every owner of the enterprise account from Organization.enterpriseOwners. That includes owners outside the configured org whose user resource was never synced. It is documented as a known limitation in docs/docs-info.md.
  • Prior — still present (confidence: low) pkg/connector/connector.go:314: under App auth, the consumed-licenses probe failure is logged at Debug, even though it predicts that the license resource type will fail the sync. L1 suggests Warn. This behavior was inherited from main.

Resolved prior findings

  • Fixed:
    • docs/connector.mdx staleness (the docs-info.md:1 and config.go:79 threads): the docs now include an Enterprise roles row and setup docs.
    • Provision capability advertised under PAT (2 threads): it is now gated on gh.newEnterpriseRoleClients != nil in connector.go.
    • Per-RPC ctx in appTokenRefresher (connector.go:618): it now uses connectorCtx.
    • Nil BaseHttpClient (connector.go:577): it is now guarded.
    • OwnerState page-bound fallthrough (enterprise_administrator_client.go:616): it now returns Internal.
    • The "sync-abort" comment (enterprise_role.go:177): corrected. Failing the sync is now intentional and documented, and this push extends that to NotFound.
    • The PathEscape rationale (customclient/client.go:57): corrected.
    • The unclosed error body (customclient/client.go:100): now closed.
  • Obsolete: the unbounded installation walk, the 404 skip logged at Debug, the startup failure with two enterprises, both memoization threads, the "documented fallback" comment and the helpers.go gRPC-status gap. That code was replaced by a single GetEnterpriseInstallation call per enterprise (a 404 there becomes FailedPrecondition, connector.go:581-594) and by the multi-enterprise rejection at client build.
Prompt for AI agents
Verify each finding against the current code and only fix it if needed.

## Suggestions

In `.github/workflows/capabilities_and_config.yaml`:
- The PR deletes this workflow, which is the only job that regenerates config_schema.json and baton_capabilities.json on push to main. Either restore it or confirm another workflow now generates and commits these artifacts, so they do not drift after future config or capability changes.

In `pkg/connector/enterprise_role.go`:
- Around line 446-466: ownerGrants emits a grant for every enterprise-account owner, including owners outside the configured org whose user resource is never synced. Consider filtering to principals that are org members, or keep the documented limitation in docs/docs-info.md if this is intentional.

In `pkg/connector/connector.go`:
- Around line 314: under GitHub App auth with --enterprises set, the consumed-licenses probe failure is logged at Debug even though it predicts the license resource type will fail the sync. Raise it to Warn so operators see it (criteria L1).

Reviewed commit: 414af6af43db

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No blocking issues found — see the full review report

@mateoHernandez123

Copy link
Copy Markdown
Contributor Author

B1 — fixed in 414af6a. Grants() no longer lets NotFound out: both phases converge on one error return, which now upgrades it to FailedPrecondition naming the enterprise. Scoped to the sync path, since Revoke still reads NotFound as "already gone" for its idempotency. The test fails with codes.NotFound (5) when the upgrade is removed.

Two corrections to the diagnosis, both checked against the live API with an installation token:

  • The trigger is not a missing Enterprise: Read. An organization the app cannot access answers errors[{type: FORBIDDEN, message: "Resource not accessible by integration"}], and enterpriseGraphQLTransport already ranks FORBIDDEN above NOT_FOUND precisely so the permission case fails loudly. That path was already correct. What does return NOT_FOUND is an organization that does not resolve.
  • A statically wrong organization never reaches Grants() — startup fails first on GET /orgs/{org}/installation with a 404, which I reproduced. The reachable case is narrower and is why the fix is still worth having: the enterprise clients are memoized once (enterprise_role.go:85-87), so in service mode an organization renamed or uninstalled while the process keeps running passes startup and then silently drops every Owner grant on each later sync.

On the non-blocking workflow item: the deletion was requested in review, and docs/docs-info.md now documents regenerating the metadata by hand plus the baton-admin flag (ci_workflows.capabilities) that restores automation for this repo.

// about known logins. The enterprise members are that candidate set, which
// means an invitation sent to someone who is not a member of the enterprise is
// invisible to the sync.
func (o *enterpriseRoleResourceType) pendingInvitationGrants(

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Heads up on an edge case: Grant() will happily invite anyone who's a user principal, but this only finds invitations for logins that come back from Enterprise.members. Outside collaborators can show up in C1 as principals through the repo collaborator grants (repository.go ~235-290), so if someone grants Owner to one of them, the invite gets created, then the next sync can't see it and C1 drops the grant even though the invite's still live on GitHub. Normal org members are fine, so it's not a big deal, but maybe reject non-members in Grant() with InvalidArgument? Or at least call it out next to the comment above.

case enterpriseOwnersPhase:
ret, nextCursor, annos, err = o.ownerGrants(ctx, client, resource, after)
case enterprisePendingPhase:
ret, nextCursor, annos, err = o.pendingInvitationGrants(ctx, client, resource, enterprise, after)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not blocking, just flagging cost: this walks the whole enterprise membership on every sync, not just the configured org. For something like 50k members that's ~500 member pages + ~500 aliased batches, so around 1k GraphQL calls back to back each sync (and every batch returns ~99 NOT_FOUND errors). Memory's fine since it streams by page token, and it's behind the opt-in flag. I'd just add a line to docs-info.md about the ~N/100 extra calls per sync so big tenants aren't surprised.

var node struct {
ID string `json:"id"`
}
if err := json.Unmarshal(raw, &node); err != nil || node.ID == "" {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small hardening thing: a json.Unmarshal error here gets treated the same as "no invitation" and we just continue. Super unlikely to happen, but if it ever does, the grant just quietly disappears from sync, which C1 reads as a revoke. I'd return the error instead. Same idea for the NOT_FOUND filter above: maybe only drop NOT_FOUNDs whose path is one of the i<N> aliases.

Related, down in pendingOwnerInvitation (~562): any codes.NotFound, including a plain HTTP 404 that the transport classifies, becomes "no invitation". The bad-slug case is already covered at client build time, so this is mostly a stray-404 thing, but a stray 404 during Revoke's post-check could hide an invite that survived.

c.org, enterprise, enterpriseMaxPages)
}

// FailedPrecondition so the caller remembers it: only a configuration

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: the comment says FailedPrecondition is "so the caller remembers it", but clients() in enterprise_role.go only caches successes and retries every failure. The real reason is that C1 treats FailedPrecondition as non-retryable, like the comment on provisioningTarget says. Maybe reword to something like "so C1 treats it as non-retryable"?

Comment thread docs/connector.mdx

Enterprise roles apply to organizations that belong to a **GitHub Enterprise Cloud** enterprise account. Enterprise Cloud is accessed at `github.com`, so it is covered by this integration — not by the separate [GitHub Enterprise](/baton/github-enterprise) integration, which is for custom domains. Skip this row if your organization does not belong to an enterprise account.

The capability is opt-in and off by default. Syncing the roles requires the **Enterprises** setting; provisioning the built-in **Enterprise Owner** role additionally requires **Enable enterprise owner provisioning** and a GitHub app installed on both the enterprise account and the organization. See the setup steps below.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line kinda reads like setting Enterprises is enough to sync roles, but that's only true with a PAT. Under App auth without the toggle you get no Owner role and the license type 403s the sync. The App setup section further down gets it right, it's just the intro that could trip someone up. Maybe add "with a personal access token" here, or link to the App note?

// only panics later inside Do.
installationClient := customclient.New(appClient)
if installationClient.BaseHttpClient == nil {
return nil, fmt.Errorf("github-connector: error building the enterprise installation client")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: the new code mostly uses baton-github:, but this one (and 570, 590) use github-connector:. Main already mixes the two, so not a regression, but it'd be nice to keep the new lines on baton-github:. Same for the unprefixed ones in graphql_transport.go and the URL/request errors in enterprise_administrator_client.go.

body, readErr := io.ReadAll(resp.Body)
_ = resp.Body.Close()
if readErr != nil {
return nil, fmt.Errorf("read GraphQL response: %w", readErr)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: no prefix here. Could be baton-github: read GraphQL response: %w to match the rest (same for creating GraphQL request in the admin client).

return nil, annos, err
}
switch {
case state.isOwner, state.pendingInvitationID != "":

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: isOwner || pendingInvitationID != "" shows up four times across Grant/Revoke (532, here, 594 negated, 617). A little func (s enterpriseOwnerState) holdsRole() bool would read nicer. Also this tagless switch is really just an if, and Revoke already uses the if form, so it'd match.

@@ -1,51 +0,0 @@
name: Generate capabilities and config schema

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question on this delete: I built the branch and ran capabilities and config, and both match the committed JSON exactly, so we're good today. But now nothing catches drift down the road. docs-info.md says baton-admin has ci_workflows.capabilities: false for this repo. Can you confirm that's true? And if so, is it worth adding a small CI drift check? Also the PR description says the capabilities command "runs in CI", which isn't the case anymore after this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants