-
Notifications
You must be signed in to change notification settings - Fork 3
feat: grant teams, repos, and org access to pending invitations #182
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -24,6 +24,13 @@ const ( | |
| invitationProfileKeyStatus = "invitation_status" | ||
| invitationProfileKeyExpiresAt = "invitation_expires_at" | ||
|
|
||
| // invitation_github_login is set only when GitHub resolved the invitee to a | ||
| // real account. Its absence is what makes an invitation unable to receive | ||
| // team or repository access directly — every GitHub membership write takes a | ||
| // username. Surfacing it lets an operator see that from C1. | ||
| invitationProfileKeyGitHubLogin = "invitation_github_login" | ||
| invitationProfileKeyRole = "invitation_role" | ||
|
|
||
| // Values exposed via invitation_status. | ||
| invitationStatusPendingAcceptance = "invitation_pending_acceptance" | ||
| invitationStatusExpired = "invitation_expired" | ||
|
|
@@ -57,6 +64,12 @@ func invitationToUserResource(invitation *github.Invitation, status string) (*v2 | |
| if expiresAt, ok := invitationExpiresAt(invitation, status); ok { | ||
| profile[invitationProfileKeyExpiresAt] = expiresAt.UTC().Format(time.RFC3339) | ||
| } | ||
| if ghLogin := invitation.GetLogin(); ghLogin != "" { | ||
| profile[invitationProfileKeyGitHubLogin] = ghLogin | ||
| } | ||
| if role := invitation.GetRole(); role != "" { | ||
| profile[invitationProfileKeyRole] = role | ||
| } | ||
|
|
||
| ret, err := resourceSdk.NewUserResource( | ||
| login, | ||
|
|
@@ -268,9 +281,25 @@ func (i *invitationResourceType) CreateAccount( | |
| return nil, nil, nil, fmt.Errorf("github-connectorv2: failed to get CreateUserParams: %w", err) | ||
| } | ||
|
|
||
| invitation, resp, err := i.client.Organizations.CreateOrgInvitation(ctx, params.org, &github.CreateOrgInvitationOptions{ | ||
| Email: params.email, | ||
| }) | ||
| // Prefer invitee_id: an invitation created that way carries a GitHub login, | ||
| // which is what lets team and repository access be pre-staged before the | ||
| // invitation is accepted. An email-only invitation has no login until (and | ||
| // unless) GitHub resolves one, and GitHub can then only attach teams by | ||
| // re-issuing the invitation. | ||
| inviteOpts := &github.CreateOrgInvitationOptions{Email: params.email} | ||
| if params.login != "" { | ||
| invitee, _, err := i.client.Users.Get(ctx, params.login) | ||
| if err != nil { | ||
| l.Debug("github-connector: could not resolve github_username, inviting by email instead", | ||
| zap.String("github_username", params.login), | ||
| zap.String("github_error", gitHubErrorMessage(err)), | ||
| ) | ||
| } else { | ||
| inviteOpts = &github.CreateOrgInvitationOptions{InviteeID: github.Ptr(invitee.GetID())} | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟡 Suggestion: replacing the whole options struct drops |
||
| } | ||
| } | ||
|
|
||
| invitation, resp, err := i.client.Organizations.CreateOrgInvitation(ctx, params.org, inviteOpts) | ||
| if err != nil { | ||
| if isAlreadyOrgMemberError(err, resp) { | ||
| memberResource, lookupErr := i.lookupUser(ctx, params.login, *params.email) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🟡 Suggestion: any
Users.Getfailure — 403 secondary rate limit, 5xx, or a real 404 — is logged atDebugand silently downgrades the account to an email-only invitation, which is exactly the case that later forces the destructivereinvite-pending-invitationspath. Per the repo's log-level criteria this non-404 fallback deservesWarn, and the discarded*github.Responsemeans the extra call's rate-limit headers never surface as aRateLimitDescriptionannotation. Consider capturingresp, distinguishing 404 (Debug) from transient failures (Warn), and merging the rate-limit annotation into the response.