openhound-github 0.6.7__tar.gz → 0.7.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (383) hide show
  1. {openhound_github-0.6.7 → openhound_github-0.7.0}/PKG-INFO +16 -3
  2. {openhound_github-0.6.7 → openhound_github-0.7.0}/README.md +15 -2
  3. openhound_github-0.7.0/descriptions/edges/GH_MemberOf.md +3 -0
  4. {openhound_github-0.6.7 → openhound_github-0.7.0}/extension/schema.json +1 -1
  5. openhound_github-0.7.0/src/openhound_github/github_rest_client.py +3 -0
  6. openhound_github-0.7.0/src/openhound_github/github_retry.py +48 -0
  7. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/helpers.py +6 -6
  8. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/lookup.py +36 -0
  9. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/main.py +2 -0
  10. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/models/__init__.py +2 -1
  11. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/models/team.py +44 -1
  12. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/resources/organization.py +236 -6
  13. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/source.py +1 -0
  14. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/transforms.py +33 -0
  15. {openhound_github-0.6.7 → openhound_github-0.7.0}/tests/test_error_resilience.py +1 -1
  16. openhound_github-0.7.0/tests/test_lookup.py +117 -0
  17. openhound_github-0.7.0/tests/test_team_external_groups.py +384 -0
  18. openhound_github-0.6.7/descriptions/edges/GH_MemberOf.md +0 -3
  19. openhound_github-0.6.7/tests/test_lookup.py +0 -28
  20. {openhound_github-0.6.7 → openhound_github-0.7.0}/.github/CODE_OF_CONDUCT.md +0 -0
  21. {openhound_github-0.6.7 → openhound_github-0.7.0}/.github/CONTRIBUTING.md +0 -0
  22. {openhound_github-0.6.7 → openhound_github-0.7.0}/.github/GOVERNANCE.md +0 -0
  23. {openhound_github-0.6.7 → openhound_github-0.7.0}/.github/GitHub-COC-Header.png +0 -0
  24. {openhound_github-0.6.7 → openhound_github-0.7.0}/.github/GitHub-CONTRIB-Header.png +0 -0
  25. {openhound_github-0.6.7 → openhound_github-0.7.0}/.github/GitHub-GOV-Header.png +0 -0
  26. {openhound_github-0.6.7 → openhound_github-0.7.0}/.github/GitHub-Header.png +0 -0
  27. {openhound_github-0.6.7 → openhound_github-0.7.0}/.github/GitHub-LIC-Header.png +0 -0
  28. {openhound_github-0.6.7 → openhound_github-0.7.0}/.github/GitHub-SEC-Header.png +0 -0
  29. {openhound_github-0.6.7 → openhound_github-0.7.0}/.github/SECURITY.md +0 -0
  30. {openhound_github-0.6.7 → openhound_github-0.7.0}/.github/SO-Dark.svg +0 -0
  31. {openhound_github-0.6.7 → openhound_github-0.7.0}/.github/SO-FOSS-Dark.svg +0 -0
  32. {openhound_github-0.6.7 → openhound_github-0.7.0}/.github/SO-FOSS-Light.svg +0 -0
  33. {openhound_github-0.6.7 → openhound_github-0.7.0}/.github/SO-Light.svg +0 -0
  34. {openhound_github-0.6.7 → openhound_github-0.7.0}/.github/workflows/publish.yml +0 -0
  35. {openhound_github-0.6.7 → openhound_github-0.7.0}/.github/workflows/release-on-merge.yml +0 -0
  36. {openhound_github-0.6.7 → openhound_github-0.7.0}/.github/workflows/validate-branch.yml +0 -0
  37. {openhound_github-0.6.7 → openhound_github-0.7.0}/.gitignore +0 -0
  38. {openhound_github-0.6.7 → openhound_github-0.7.0}/.gitmodules +0 -0
  39. {openhound_github-0.6.7 → openhound_github-0.7.0}/.pre-commit-config.yaml +0 -0
  40. {openhound_github-0.6.7 → openhound_github-0.7.0}/LICENSE.md +0 -0
  41. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_AddAssignee.md +0 -0
  42. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_AddCollaborator.md +0 -0
  43. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_AddLabel.md +0 -0
  44. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_AddMember.md +0 -0
  45. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_AdminTo.md +0 -0
  46. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_ApprovesDeploymentTo.md +0 -0
  47. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_AssignedTo.md +0 -0
  48. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_BypassBranchProtection.md +0 -0
  49. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_BypassPullRequestAllowances.md +0 -0
  50. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_CallsWorkflow.md +0 -0
  51. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_CanAccess.md +0 -0
  52. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_CanAssumeIdentity.md +0 -0
  53. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_CanCreateBranch.md +0 -0
  54. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_CanCreateEnvironment.md +0 -0
  55. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_CanCreateRepositoryWithRunnerAccess.md +0 -0
  56. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_CanDeployToEnvironment.md +0 -0
  57. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_CanEditEnvironment.md +0 -0
  58. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_CanEditProtection.md +0 -0
  59. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_CanPwnRequest.md +0 -0
  60. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_CanReadSecretScanningAlert.md +0 -0
  61. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_CanUseRunner.md +0 -0
  62. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_CanWriteBranch.md +0 -0
  63. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_CloseDiscussion.md +0 -0
  64. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_CloseIssue.md +0 -0
  65. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_ClosePullRequest.md +0 -0
  66. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_Contains.md +0 -0
  67. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_ConvertIssuesToDiscussions.md +0 -0
  68. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_CreateDiscussionCategory.md +0 -0
  69. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_CreateRepository.md +0 -0
  70. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_CreateSoloMergeQueueEntry.md +0 -0
  71. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_CreateTag.md +0 -0
  72. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_CreateTeam.md +0 -0
  73. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_DeleteAlertsCodeScanning.md +0 -0
  74. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_DeleteDiscussion.md +0 -0
  75. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_DeleteDiscussionComment.md +0 -0
  76. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_DeleteIssue.md +0 -0
  77. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_DeleteTag.md +0 -0
  78. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_DependsOn.md +0 -0
  79. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_DeploysTo.md +0 -0
  80. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_EditCategoryOnDiscussion.md +0 -0
  81. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_EditDiscussionCategory.md +0 -0
  82. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_EditDiscussionComment.md +0 -0
  83. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_EditRepoAnnouncementBanners.md +0 -0
  84. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_EditRepoCustomPropertiesValues.md +0 -0
  85. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_EditRepoMetadata.md +0 -0
  86. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_EditRepoProtections.md +0 -0
  87. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_HasBaseRole.md +0 -0
  88. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_HasBranch.md +0 -0
  89. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_HasEnvironment.md +0 -0
  90. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_HasExternalIdentity.md +0 -0
  91. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_HasJob.md +0 -0
  92. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_HasMember.md +0 -0
  93. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_HasPersonalAccessToken.md +0 -0
  94. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_HasPersonalAccessTokenRequest.md +0 -0
  95. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_HasRole.md +0 -0
  96. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_HasRunner.md +0 -0
  97. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_HasSamlIdentityProvider.md +0 -0
  98. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_HasSecret.md +0 -0
  99. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_HasStep.md +0 -0
  100. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_HasVariable.md +0 -0
  101. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_HasWorkflow.md +0 -0
  102. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_InheritedFrom.md +0 -0
  103. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_InstalledAs.md +0 -0
  104. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_InviteMember.md +0 -0
  105. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_IsEligibleFor.md +0 -0
  106. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_JumpMergeQueue.md +0 -0
  107. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_ManageDeployKeys.md +0 -0
  108. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_ManageDiscussionBadges.md +0 -0
  109. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_ManageOrganizationWebhooks.md +0 -0
  110. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_ManageRepoSecurityProducts.md +0 -0
  111. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_ManageSecurityProducts.md +0 -0
  112. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_ManageSettingsMergeTypes.md +0 -0
  113. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_ManageSettingsPages.md +0 -0
  114. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_ManageSettingsProjects.md +0 -0
  115. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_ManageSettingsWiki.md +0 -0
  116. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_ManageTopics.md +0 -0
  117. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_ManageWebhooks.md +0 -0
  118. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_MapsToUser.md +0 -0
  119. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_MarkAsDuplicate.md +0 -0
  120. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_MatchesEnvironmentPolicy.md +0 -0
  121. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_OrgBypassCodeScanningDismissalRequests.md +0 -0
  122. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_OrgBypassSecretScanningClosureRequests.md +0 -0
  123. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_OrgReviewAndManageSecretScanningBypassRequests.md +0 -0
  124. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_OrgReviewAndManageSecretScanningClosureRequests.md +0 -0
  125. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_Owns.md +0 -0
  126. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_ProtectedBy.md +0 -0
  127. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_PushProtectedBranch.md +0 -0
  128. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_ReadCodeScanning.md +0 -0
  129. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_ReadOrganizationActionsUsageMetrics.md +0 -0
  130. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_ReadOrganizationCustomOrgRole.md +0 -0
  131. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_ReadOrganizationCustomRepoRole.md +0 -0
  132. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_ReadRepoContents.md +0 -0
  133. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_RemoveAssignee.md +0 -0
  134. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_RemoveLabel.md +0 -0
  135. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_ReopenDiscussion.md +0 -0
  136. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_ReopenIssue.md +0 -0
  137. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_ReopenPullRequest.md +0 -0
  138. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_RequestPrReview.md +0 -0
  139. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_ResolveDependabotAlerts.md +0 -0
  140. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_ResolveSecretScanningAlerts.md +0 -0
  141. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_RestrictionsCanPush.md +0 -0
  142. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_RunOrgMigration.md +0 -0
  143. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_SetInteractionLimits.md +0 -0
  144. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_SetIssueType.md +0 -0
  145. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_SetMilestone.md +0 -0
  146. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_SetSocialPreview.md +0 -0
  147. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_SyncedTo.md +0 -0
  148. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_ToggleDiscussionAnswer.md +0 -0
  149. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_ToggleDiscussionCommentMinimize.md +0 -0
  150. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_TransferRepository.md +0 -0
  151. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_UsesSecret.md +0 -0
  152. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_UsesVariable.md +0 -0
  153. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_ValidToken.md +0 -0
  154. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_ViewDependabotAlerts.md +0 -0
  155. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_ViewSecretScanningAlerts.md +0 -0
  156. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_WriteCodeScanning.md +0 -0
  157. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_WriteOrganizationActionsSecrets.md +0 -0
  158. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_WriteOrganizationActionsSettings.md +0 -0
  159. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_WriteOrganizationActionsVariables.md +0 -0
  160. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_WriteOrganizationCustomOrgRole.md +0 -0
  161. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_WriteOrganizationCustomRepoRole.md +0 -0
  162. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_WriteOrganizationNetworkConfigurations.md +0 -0
  163. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_WriteRepoContents.md +0 -0
  164. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/edges/GH_WriteRepoPullRequests.md +0 -0
  165. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/nodes/GH_App.md +0 -0
  166. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/nodes/GH_AppInstallation.md +0 -0
  167. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/nodes/GH_Branch.md +0 -0
  168. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/nodes/GH_BranchProtectionRule.md +0 -0
  169. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/nodes/GH_EnterpriseRunner.md +0 -0
  170. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/nodes/GH_EnterpriseRunnerGroup.md +0 -0
  171. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/nodes/GH_Environment.md +0 -0
  172. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/nodes/GH_EnvironmentBranchPolicy.md +0 -0
  173. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/nodes/GH_EnvironmentSecret.md +0 -0
  174. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/nodes/GH_EnvironmentVariable.md +0 -0
  175. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/nodes/GH_ExternalIdentity.md +0 -0
  176. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/nodes/GH_OrgRole.md +0 -0
  177. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/nodes/GH_OrgRunner.md +0 -0
  178. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/nodes/GH_OrgRunnerGroup.md +0 -0
  179. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/nodes/GH_OrgSecret.md +0 -0
  180. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/nodes/GH_OrgVariable.md +0 -0
  181. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/nodes/GH_Organization.md +0 -0
  182. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/nodes/GH_PersonalAccessToken.md +0 -0
  183. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/nodes/GH_PersonalAccessTokenRequest.md +0 -0
  184. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/nodes/GH_RepoRole.md +0 -0
  185. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/nodes/GH_RepoRunner.md +0 -0
  186. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/nodes/GH_RepoSecret.md +0 -0
  187. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/nodes/GH_RepoVariable.md +0 -0
  188. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/nodes/GH_Repository.md +0 -0
  189. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/nodes/GH_SamlIdentityProvider.md +0 -0
  190. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/nodes/GH_SecretScanningAlert.md +0 -0
  191. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/nodes/GH_Team.md +0 -0
  192. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/nodes/GH_TeamRole.md +0 -0
  193. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/nodes/GH_User.md +0 -0
  194. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/nodes/GH_Workflow.md +0 -0
  195. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/nodes/GH_WorkflowJob.md +0 -0
  196. {openhound_github-0.6.7 → openhound_github-0.7.0}/descriptions/nodes/GH_WorkflowStep.md +0 -0
  197. {openhound_github-0.6.7 → openhound_github-0.7.0}/docs/og-docs.json +0 -0
  198. {openhound_github-0.6.7 → openhound_github-0.7.0}/extension/privilege_zone_rules/t0-all-repo-admin-role.json +0 -0
  199. {openhound_github-0.6.7 → openhound_github-0.7.0}/extension/privilege_zone_rules/t0-app-installations-all-repos.json +0 -0
  200. {openhound_github-0.6.7 → openhound_github-0.7.0}/extension/privilege_zone_rules/t0-apps-all-repos.json +0 -0
  201. {openhound_github-0.6.7 → openhound_github-0.7.0}/extension/privilege_zone_rules/t0-external-identities-owners.json +0 -0
  202. {openhound_github-0.6.7 → openhound_github-0.7.0}/extension/privilege_zone_rules/t0-organizations.json +0 -0
  203. {openhound_github-0.6.7 → openhound_github-0.7.0}/extension/privilege_zone_rules/t0-owner-users.json +0 -0
  204. {openhound_github-0.6.7 → openhound_github-0.7.0}/extension/privilege_zone_rules/t0-owners-role.json +0 -0
  205. {openhound_github-0.6.7 → openhound_github-0.7.0}/extension/privilege_zone_rules/t0-pats-all-repos.json +0 -0
  206. {openhound_github-0.6.7 → openhound_github-0.7.0}/extension/privilege_zone_rules/t0-privilege-escalation-roles.json +0 -0
  207. {openhound_github-0.6.7 → openhound_github-0.7.0}/extension/privilege_zone_rules/t0-privilege-escalation-users.json +0 -0
  208. {openhound_github-0.6.7 → openhound_github-0.7.0}/extension/privilege_zone_rules/t0-saml-identity-providers.json +0 -0
  209. {openhound_github-0.6.7 → openhound_github-0.7.0}/extension/saved_searches/README.md +0 -0
  210. {openhound_github-0.6.7 → openhound_github-0.7.0}/extension/saved_searches/actions-sha-pinning-not-required.json +0 -0
  211. {openhound_github-0.6.7 → openhound_github-0.7.0}/extension/saved_searches/active-leaked-secrets.json +0 -0
  212. {openhound_github-0.6.7 → openhound_github-0.7.0}/extension/saved_searches/advanced-security-disabled-new-repos.json +0 -0
  213. {openhound_github-0.6.7 → openhound_github-0.7.0}/extension/saved_searches/all-actions-allowed.json +0 -0
  214. {openhound_github-0.6.7 → openhound_github-0.7.0}/extension/saved_searches/app-installations-all-repos.json +0 -0
  215. {openhound_github-0.6.7 → openhound_github-0.7.0}/extension/saved_searches/branch-protection-admins-not-enforced.json +0 -0
  216. {openhound_github-0.6.7 → openhound_github-0.7.0}/extension/saved_searches/branch-protection-deletions-allowed.json +0 -0
  217. {openhound_github-0.6.7 → openhound_github-0.7.0}/extension/saved_searches/branch-protection-force-pushes.json +0 -0
  218. {openhound_github-0.6.7 → openhound_github-0.7.0}/extension/saved_searches/branch-protection-no-code-owner-reviews.json +0 -0
  219. {openhound_github-0.6.7 → openhound_github-0.7.0}/extension/saved_searches/branch-protection-no-pr-reviews.json +0 -0
  220. {openhound_github-0.6.7 → openhound_github-0.7.0}/extension/saved_searches/branch-protection-no-status-checks.json +0 -0
  221. {openhound_github-0.6.7 → openhound_github-0.7.0}/extension/saved_searches/branch-protection-self-approval.json +0 -0
  222. {openhound_github-0.6.7 → openhound_github-0.7.0}/extension/saved_searches/branch-protection-stale-reviews.json +0 -0
  223. {openhound_github-0.6.7 → openhound_github-0.7.0}/extension/saved_searches/bypass-pr-requirements.json +0 -0
  224. {openhound_github-0.6.7 → openhound_github-0.7.0}/extension/saved_searches/dangerous-branch-perms.json +0 -0
  225. {openhound_github-0.6.7 → openhound_github-0.7.0}/extension/saved_searches/default-repository-permissions.json +0 -0
  226. {openhound_github-0.6.7 → openhound_github-0.7.0}/extension/saved_searches/demo-sso-to-cloud-round-trip.json +0 -0
  227. {openhound_github-0.6.7 → openhound_github-0.7.0}/extension/saved_searches/dependabot-alerts-disabled-new-repos.json +0 -0
  228. {openhound_github-0.6.7 → openhound_github-0.7.0}/extension/saved_searches/dependabot-updates-disabled-new-repos.json +0 -0
  229. {openhound_github-0.6.7 → openhound_github-0.7.0}/extension/saved_searches/dependency-graph-disabled-new-repos.json +0 -0
  230. {openhound_github-0.6.7 → openhound_github-0.7.0}/extension/saved_searches/environments-admin-bypass.json +0 -0
  231. {openhound_github-0.6.7 → openhound_github-0.7.0}/extension/saved_searches/expired-pats.json +0 -0
  232. {openhound_github-0.6.7 → openhound_github-0.7.0}/extension/saved_searches/external-identities-without-scim.json +0 -0
  233. {openhound_github-0.6.7 → openhound_github-0.7.0}/extension/saved_searches/github-to-azure-identity.json +0 -0
  234. {openhound_github-0.6.7 → openhound_github-0.7.0}/extension/saved_searches/global-repo-perms.json +0 -0
  235. {openhound_github-0.6.7 → openhound_github-0.7.0}/extension/saved_searches/hybrid-identities.json +0 -0
  236. {openhound_github-0.6.7 → openhound_github-0.7.0}/extension/saved_searches/members-can-change-repo-visibility.json +0 -0
  237. {openhound_github-0.6.7 → openhound_github-0.7.0}/extension/saved_searches/members-can-create-pages.json +0 -0
  238. {openhound_github-0.6.7 → openhound_github-0.7.0}/extension/saved_searches/members-can-create-public-repos.json +0 -0
  239. {openhound_github-0.6.7 → openhound_github-0.7.0}/extension/saved_searches/members-can-delete-repos.json +0 -0
  240. {openhound_github-0.6.7 → openhound_github-0.7.0}/extension/saved_searches/members-can-fork-private-repos.json +0 -0
  241. {openhound_github-0.6.7 → openhound_github-0.7.0}/extension/saved_searches/members-can-invite-outside-collaborators.json +0 -0
  242. {openhound_github-0.6.7 → openhound_github-0.7.0}/extension/saved_searches/org-owners.json +0 -0
  243. {openhound_github-0.6.7 → openhound_github-0.7.0}/extension/saved_searches/orgs-without-2fa.json +0 -0
  244. {openhound_github-0.6.7 → openhound_github-0.7.0}/extension/saved_searches/pats-all-repo-access.json +0 -0
  245. {openhound_github-0.6.7 → openhound_github-0.7.0}/extension/saved_searches/pending-pat-requests.json +0 -0
  246. {openhound_github-0.6.7 → openhound_github-0.7.0}/extension/saved_searches/private-repos-forking-allowed.json +0 -0
  247. {openhound_github-0.6.7 → openhound_github-0.7.0}/extension/saved_searches/privileged-custom-org-roles.json +0 -0
  248. {openhound_github-0.6.7 → openhound_github-0.7.0}/extension/saved_searches/privileged-hybrid-identities.json +0 -0
  249. {openhound_github-0.6.7 → openhound_github-0.7.0}/extension/saved_searches/public-repos.json +0 -0
  250. {openhound_github-0.6.7 → openhound_github-0.7.0}/extension/saved_searches/push-protection-disabled-new-repos.json +0 -0
  251. {openhound_github-0.6.7 → openhound_github-0.7.0}/extension/saved_searches/push-to-protected-branches.json +0 -0
  252. {openhound_github-0.6.7 → openhound_github-0.7.0}/extension/saved_searches/repos-secret-scanning-disabled.json +0 -0
  253. {openhound_github-0.6.7 → openhound_github-0.7.0}/extension/saved_searches/repos-vulnerable-to-workflow-secret-exfil.json +0 -0
  254. {openhound_github-0.6.7 → openhound_github-0.7.0}/extension/saved_searches/repository-workflows.json +0 -0
  255. {openhound_github-0.6.7 → openhound_github-0.7.0}/extension/saved_searches/saml-configuration.json +0 -0
  256. {openhound_github-0.6.7 → openhound_github-0.7.0}/extension/saved_searches/secret-scanning-alerts.json +0 -0
  257. {openhound_github-0.6.7 → openhound_github-0.7.0}/extension/saved_searches/secret-scanning-disabled-new-repos.json +0 -0
  258. {openhound_github-0.6.7 → openhound_github-0.7.0}/extension/saved_searches/secrets-reachable-by-user.json +0 -0
  259. {openhound_github-0.6.7 → openhound_github-0.7.0}/extension/saved_searches/team-membership-admin.json +0 -0
  260. {openhound_github-0.6.7 → openhound_github-0.7.0}/extension/saved_searches/team-structure.json +0 -0
  261. {openhound_github-0.6.7 → openhound_github-0.7.0}/extension/saved_searches/unprotected-branches.json +0 -0
  262. {openhound_github-0.6.7 → openhound_github-0.7.0}/extension/saved_searches/unprotected-default-branch-with-workflow.json +0 -0
  263. {openhound_github-0.6.7 → openhound_github-0.7.0}/extension/saved_searches/unprotected-default-branches.json +0 -0
  264. {openhound_github-0.6.7 → openhound_github-0.7.0}/extension/saved_searches/web-commit-signoff-not-required.json +0 -0
  265. {openhound_github-0.6.7 → openhound_github-0.7.0}/justfile +0 -0
  266. {openhound_github-0.6.7 → openhound_github-0.7.0}/pyproject.toml +0 -0
  267. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/main.py +0 -0
  268. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/__init__.py +0 -0
  269. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/auth.py +0 -0
  270. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/extension.yaml +0 -0
  271. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/graph.py +0 -0
  272. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/graphql.py +0 -0
  273. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/kinds/edges.py +0 -0
  274. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/kinds/nodes.py +0 -0
  275. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/models/actions_permission.py +0 -0
  276. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/models/app_installation.py +0 -0
  277. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/models/branch.py +0 -0
  278. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/models/branch_pr_bypass_allowance.py +0 -0
  279. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/models/branch_protection_rule.py +0 -0
  280. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/models/branch_push_allowance.py +0 -0
  281. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/models/enterprise.py +0 -0
  282. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/models/enterprise_admin.py +0 -0
  283. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/models/enterprise_helpers.py +0 -0
  284. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/models/enterprise_managed_user.py +0 -0
  285. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/models/enterprise_member.py +0 -0
  286. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/models/enterprise_organization.py +0 -0
  287. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/models/enterprise_role.py +0 -0
  288. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/models/enterprise_role_team.py +0 -0
  289. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/models/enterprise_role_user.py +0 -0
  290. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/models/enterprise_team.py +0 -0
  291. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/models/enterprise_team_member.py +0 -0
  292. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/models/enterprise_team_organization.py +0 -0
  293. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/models/enterprise_team_role.py +0 -0
  294. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/models/enterprise_user.py +0 -0
  295. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/models/env_secret.py +0 -0
  296. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/models/env_variable.py +0 -0
  297. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/models/environment.py +0 -0
  298. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/models/environment_branch_policy.py +0 -0
  299. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/models/external_identity.py +0 -0
  300. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/models/org.py +0 -0
  301. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/models/org_role.py +0 -0
  302. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/models/org_role_member.py +0 -0
  303. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/models/org_role_team.py +0 -0
  304. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/models/org_secret.py +0 -0
  305. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/models/org_variable.py +0 -0
  306. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/models/personal_access_token.py +0 -0
  307. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/models/personal_access_token_access.py +0 -0
  308. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/models/personal_access_token_request.py +0 -0
  309. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/models/projected_enterprise_team.py +0 -0
  310. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/models/repo_role_assignment.py +0 -0
  311. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/models/repository.py +0 -0
  312. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/models/repository_role.py +0 -0
  313. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/models/repository_secret.py +0 -0
  314. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/models/repository_variable.py +0 -0
  315. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/models/runner.py +0 -0
  316. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/models/saml_assertion_consumer_service.py +0 -0
  317. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/models/saml_helpers.py +0 -0
  318. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/models/saml_issuer.py +0 -0
  319. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/models/saml_provider.py +0 -0
  320. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/models/saml_service_provider.py +0 -0
  321. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/models/scim_user.py +0 -0
  322. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/models/secret_scanning_alert.py +0 -0
  323. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/models/team_member.py +0 -0
  324. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/models/team_role.py +0 -0
  325. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/models/user.py +0 -0
  326. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/models/workflow.py +0 -0
  327. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/models/workflow_job.py +0 -0
  328. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/models/workflow_step.py +0 -0
  329. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/resources/__init__.py +0 -0
  330. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/resources/enterprise.py +0 -0
  331. {openhound_github-0.6.7 → openhound_github-0.7.0}/src/openhound_github/runner_ids.py +0 -0
  332. {openhound_github-0.6.7 → openhound_github-0.7.0}/tests/test_app_auth.py +0 -0
  333. {openhound_github-0.6.7 → openhound_github-0.7.0}/tests/test_branch_collection_gate.py +0 -0
  334. {openhound_github-0.6.7 → openhound_github-0.7.0}/tests/test_branch_protection_traversability.py +0 -0
  335. {openhound_github-0.6.7 → openhound_github-0.7.0}/tests/test_data/api/actions-permissions.json +0 -0
  336. {openhound_github-0.6.7 → openhound_github-0.7.0}/tests/test_data/api/actionsecrets.json +0 -0
  337. {openhound_github-0.6.7 → openhound_github-0.7.0}/tests/test_data/api/app.json +0 -0
  338. {openhound_github-0.6.7 → openhound_github-0.7.0}/tests/test_data/api/appinstalls.json +0 -0
  339. {openhound_github-0.6.7 → openhound_github-0.7.0}/tests/test_data/api/branch-policies.json +0 -0
  340. {openhound_github-0.6.7 → openhound_github-0.7.0}/tests/test_data/api/branch-prot-rules.json +0 -0
  341. {openhound_github-0.6.7 → openhound_github-0.7.0}/tests/test_data/api/branches.json +0 -0
  342. {openhound_github-0.6.7 → openhound_github-0.7.0}/tests/test_data/api/custom-roles.json +0 -0
  343. {openhound_github-0.6.7 → openhound_github-0.7.0}/tests/test_data/api/environments.json +0 -0
  344. {openhound_github-0.6.7 → openhound_github-0.7.0}/tests/test_data/api/org-pat-request.json +0 -0
  345. {openhound_github-0.6.7 → openhound_github-0.7.0}/tests/test_data/api/org-pat.json +0 -0
  346. {openhound_github-0.6.7 → openhound_github-0.7.0}/tests/test_data/api/org-role-teams.json +0 -0
  347. {openhound_github-0.6.7 → openhound_github-0.7.0}/tests/test_data/api/org-role-users.json +0 -0
  348. {openhound_github-0.6.7 → openhound_github-0.7.0}/tests/test_data/api/org-roles.json +0 -0
  349. {openhound_github-0.6.7 → openhound_github-0.7.0}/tests/test_data/api/org.json +0 -0
  350. {openhound_github-0.6.7 → openhound_github-0.7.0}/tests/test_data/api/pat-repositories.json +0 -0
  351. {openhound_github-0.6.7 → openhound_github-0.7.0}/tests/test_data/api/repo-collaborators.json +0 -0
  352. {openhound_github-0.6.7 → openhound_github-0.7.0}/tests/test_data/api/repo-teams.json +0 -0
  353. {openhound_github-0.6.7 → openhound_github-0.7.0}/tests/test_data/api/repositories.json +0 -0
  354. {openhound_github-0.6.7 → openhound_github-0.7.0}/tests/test_data/api/scimusers.json +0 -0
  355. {openhound_github-0.6.7 → openhound_github-0.7.0}/tests/test_data/api/secrets.json +0 -0
  356. {openhound_github-0.6.7 → openhound_github-0.7.0}/tests/test_data/api/secretscanningalert.json +0 -0
  357. {openhound_github-0.6.7 → openhound_github-0.7.0}/tests/test_data/api/selected-org-secrets.json +0 -0
  358. {openhound_github-0.6.7 → openhound_github-0.7.0}/tests/test_data/api/variables.json +0 -0
  359. {openhound_github-0.6.7 → openhound_github-0.7.0}/tests/test_data/api/workflows.json +0 -0
  360. {openhound_github-0.6.7 → openhound_github-0.7.0}/tests/test_enterprise_capabilities.py +0 -0
  361. {openhound_github-0.6.7 → openhound_github-0.7.0}/tests/test_enterprise_organization.py +0 -0
  362. {openhound_github-0.6.7 → openhound_github-0.7.0}/tests/test_enterprise_resources.py +0 -0
  363. {openhound_github-0.6.7 → openhound_github-0.7.0}/tests/test_environment_model.py +0 -0
  364. {openhound_github-0.6.7 → openhound_github-0.7.0}/tests/test_environment_resources.py +0 -0
  365. {openhound_github-0.6.7 → openhound_github-0.7.0}/tests/test_environment_reviewer_lookup.py +0 -0
  366. {openhound_github-0.6.7 → openhound_github-0.7.0}/tests/test_github_app_retry.py +0 -0
  367. {openhound_github-0.6.7 → openhound_github-0.7.0}/tests/test_github_rest_client.py +0 -0
  368. {openhound_github-0.6.7 → openhound_github-0.7.0}/tests/test_github_retry.py +0 -0
  369. {openhound_github-0.6.7 → openhound_github-0.7.0}/tests/test_helpers.py +0 -0
  370. {openhound_github-0.6.7 → openhound_github-0.7.0}/tests/test_org_scim_resources.py +0 -0
  371. {openhound_github-0.6.7 → openhound_github-0.7.0}/tests/test_org_secret_models.py +0 -0
  372. {openhound_github-0.6.7 → openhound_github-0.7.0}/tests/test_repository_rulesets.py +0 -0
  373. {openhound_github-0.6.7 → openhound_github-0.7.0}/tests/test_runner_ids.py +0 -0
  374. {openhound_github-0.6.7 → openhound_github-0.7.0}/tests/test_runner_models.py +0 -0
  375. {openhound_github-0.6.7 → openhound_github-0.7.0}/tests/test_runner_resources.py +0 -0
  376. {openhound_github-0.6.7 → openhound_github-0.7.0}/tests/test_saml_helpers.py +0 -0
  377. {openhound_github-0.6.7 → openhound_github-0.7.0}/tests/test_saml_models.py +0 -0
  378. {openhound_github-0.6.7 → openhound_github-0.7.0}/tests/test_scim_models.py +0 -0
  379. {openhound_github-0.6.7 → openhound_github-0.7.0}/tests/test_source_endpoints.py +0 -0
  380. {openhound_github-0.6.7 → openhound_github-0.7.0}/tests/test_source_org_canonicalization.py +0 -0
  381. {openhound_github-0.6.7 → openhound_github-0.7.0}/tests/test_variable_models.py +0 -0
  382. {openhound_github-0.6.7 → openhound_github-0.7.0}/tests/test_workflow_model.py +0 -0
  383. {openhound_github-0.6.7 → openhound_github-0.7.0}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: openhound-github
3
- Version: 0.6.7
3
+ Version: 0.7.0
4
4
  Summary: Github collector for OpenHound
5
5
  Author-email: "jdreijer@specterops.io" <jdreijer@specterops.io>, Jared Atkinson <jatkinson@specterops.io>
6
6
  License-File: LICENSE.md
@@ -74,10 +74,23 @@ A token with enterprise SCIM access is used to collect both `/scim/v2/enterprise
74
74
 
75
75
  Enterprise roles, including the built-in `members` role, are emitted through `GH_HasRole` and granular enterprise capability relationships. Only capability relationships with a confirmed privilege path are traversable; descriptive permissions such as `GH_WriteEnterpriseSso` remain non-traversable.
76
76
 
77
+ ### Optional privileged collection
78
+
79
+ The collector runs successfully with the documented read-only permission set. Some higher-fidelity relationships require optional non-read-only permissions because GitHub exposes the supporting read APIs behind privileged permission names:
80
+
81
+ - Organization `Members: write` enables external group mapping collection for IdP-synced teams, which allows the converter to emit `SCIM_Provisioned` edges from `SCIM_Group` to `GH_Team`. This is useful when the organization uses team synchronization with an external identity provider; if no GitHub teams are linked to external groups, this permission does not add graph data.
82
+ - Classic PAT scope `manage_runners:enterprise` enables enterprise self-hosted runner group and runner collection. This is useful when the enterprise has enterprise-scoped runner groups or runners, especially runner groups shared into organizations; if all runners are organization- or repository-scoped, this scope does not add graph data.
83
+
84
+ If these optional permissions are not granted, OpenHound skips the affected resources and continues collecting the rest of the GitHub environment.
85
+
77
86
  [![Python Version](https://img.shields.io/badge/Python-3.13-brightgreen.svg)](#about)
78
87
 
79
88
  ## Getting Started
80
89
 
81
- Follow the OpenHound docs to get started:
90
+ Follow the OpenHound GitHub collector docs to get started:
82
91
 
83
- - [OpenHound Documentation](https://bloodhound.specterops.io/openhound/overview)
92
+ - [GitHub collector overview](https://bloodhound.specterops.io/openhound/collectors/github/overview)
93
+ - [Configure the collector](https://bloodhound.specterops.io/openhound/collectors/github/collect-data)
94
+ - [Configure an organization GitHub App](https://bloodhound.specterops.io/openhound/collectors/github/configure-app)
95
+ - [Configure an enterprise GitHub App](https://bloodhound.specterops.io/openhound/collectors/github/configure-enterprise-app)
96
+ - [Configure a personal access token](https://bloodhound.specterops.io/openhound/collectors/github/configure-pat)
@@ -63,10 +63,23 @@ A token with enterprise SCIM access is used to collect both `/scim/v2/enterprise
63
63
 
64
64
  Enterprise roles, including the built-in `members` role, are emitted through `GH_HasRole` and granular enterprise capability relationships. Only capability relationships with a confirmed privilege path are traversable; descriptive permissions such as `GH_WriteEnterpriseSso` remain non-traversable.
65
65
 
66
+ ### Optional privileged collection
67
+
68
+ The collector runs successfully with the documented read-only permission set. Some higher-fidelity relationships require optional non-read-only permissions because GitHub exposes the supporting read APIs behind privileged permission names:
69
+
70
+ - Organization `Members: write` enables external group mapping collection for IdP-synced teams, which allows the converter to emit `SCIM_Provisioned` edges from `SCIM_Group` to `GH_Team`. This is useful when the organization uses team synchronization with an external identity provider; if no GitHub teams are linked to external groups, this permission does not add graph data.
71
+ - Classic PAT scope `manage_runners:enterprise` enables enterprise self-hosted runner group and runner collection. This is useful when the enterprise has enterprise-scoped runner groups or runners, especially runner groups shared into organizations; if all runners are organization- or repository-scoped, this scope does not add graph data.
72
+
73
+ If these optional permissions are not granted, OpenHound skips the affected resources and continues collecting the rest of the GitHub environment.
74
+
66
75
  [![Python Version](https://img.shields.io/badge/Python-3.13-brightgreen.svg)](#about)
67
76
 
68
77
  ## Getting Started
69
78
 
70
- Follow the OpenHound docs to get started:
79
+ Follow the OpenHound GitHub collector docs to get started:
71
80
 
72
- - [OpenHound Documentation](https://bloodhound.specterops.io/openhound/overview)
81
+ - [GitHub collector overview](https://bloodhound.specterops.io/openhound/collectors/github/overview)
82
+ - [Configure the collector](https://bloodhound.specterops.io/openhound/collectors/github/collect-data)
83
+ - [Configure an organization GitHub App](https://bloodhound.specterops.io/openhound/collectors/github/configure-app)
84
+ - [Configure an enterprise GitHub App](https://bloodhound.specterops.io/openhound/collectors/github/configure-enterprise-app)
85
+ - [Configure a personal access token](https://bloodhound.specterops.io/openhound/collectors/github/configure-pat)
@@ -0,0 +1,3 @@
1
+ ## General Information
2
+
3
+ The traversable GH_MemberOf edge represents team membership and projection relationships, linking a team role to its parent team, a child team to a parent team in nested team hierarchies, or a GH_EnterpriseTeam to its projected GH_Team in an organization. This edge is traversable because these relationships carry effective team membership context through the graph: a user who holds a role in a child team inherits the repository permissions of ancestor teams, and enterprise-managed team membership flows into the projected organization team.
@@ -467,7 +467,7 @@
467
467
  },
468
468
  {
469
469
  "name": "GH_MemberOf",
470
- "description": "Team role is a member of a team, or team is a nested member of a parent team",
470
+ "description": "Team role is a member of a team, team is nested under a parent team, or enterprise team maps to its projected organization team",
471
471
  "is_traversable": true
472
472
  },
473
473
  {
@@ -0,0 +1,3 @@
1
+ from openhound_github.github_retry import should_retry_github_response
2
+
3
+ __all__ = ["should_retry_github_response"]
@@ -0,0 +1,48 @@
1
+ from typing import Optional
2
+
3
+ from requests import Response
4
+
5
+
6
+ def _response_message(response: Response) -> str:
7
+ try:
8
+ response_data = response.json()
9
+ except ValueError:
10
+ return getattr(response, "text", "")
11
+ if isinstance(response_data, dict):
12
+ return str(response_data.get("message", ""))
13
+ return ""
14
+
15
+
16
+ def is_primary_rate_limit_response(response: Response) -> bool:
17
+ if response.status_code not in (403, 429):
18
+ return False
19
+
20
+ message = _response_message(response).lower()
21
+ return (
22
+ response.headers.get("x-ratelimit-remaining") == "0"
23
+ or "api rate limit exceeded" in message
24
+ )
25
+
26
+
27
+ def is_secondary_rate_limit_response(response: Response) -> bool:
28
+ if response.status_code not in (403, 429):
29
+ return False
30
+
31
+ message = _response_message(response).lower()
32
+ return "secondary rate limit" in message or "abuse detection" in message
33
+
34
+
35
+ def should_retry_github_response(
36
+ response: Optional[Response], exception: Optional[BaseException]
37
+ ) -> bool:
38
+ if response is None:
39
+ return False
40
+
41
+ return (
42
+ is_primary_rate_limit_response(response)
43
+ or is_secondary_rate_limit_response(response)
44
+ or (
45
+ response.status_code in (403, 429)
46
+ and bool(response.headers.get("Retry-After"))
47
+ )
48
+ )
@@ -14,6 +14,10 @@ from dlt.sources.helpers.rest_client.paginators import (
14
14
  from requests import Request
15
15
 
16
16
  from openhound_github.auth import GitHubAppInstallationAuth
17
+ from openhound_github.github_retry import (
18
+ is_primary_rate_limit_response,
19
+ is_secondary_rate_limit_response,
20
+ )
17
21
 
18
22
  logger = logging.getLogger(__name__)
19
23
 
@@ -439,18 +443,14 @@ def github_retry_policy(auth: AuthConfigBase):
439
443
  if response.status_code not in (403, 429):
440
444
  return False
441
445
 
442
- message = _response_message(response).lower()
443
- if (
444
- headers.get("x-ratelimit-remaining") == "0"
445
- or "api rate limit exceeded" in message
446
- ):
446
+ if is_primary_rate_limit_response(response):
447
447
  reset_at = headers.get("x-ratelimit-reset")
448
448
  delay = int(reset_at) - now if reset_at else 0
449
449
  headers["Retry-After"] = str(delay)
450
450
  logger.warning("Primary rate limit reached, retrying in %s seconds", delay)
451
451
  return True
452
452
 
453
- if "secondary rate limit" in message or "abuse detection" in message:
453
+ if is_secondary_rate_limit_response(response):
454
454
  logger.warning("Secondary rate limit reached, retrying in 60 seconds")
455
455
  headers["Retry-After"] = "60"
456
456
  return True
@@ -205,6 +205,42 @@ class GithubLookup(LookupManager):
205
205
  [org_login, slug],
206
206
  )
207
207
 
208
+ @lru_cache
209
+ def external_group_for_team(
210
+ self, org_login: str, team_database_id: int
211
+ ) -> tuple[int, str] | None:
212
+ row = self._find_single_row(
213
+ f"""
214
+ SELECT external_group_id, external_group_name
215
+ FROM {self.schema}.team_external_groups
216
+ WHERE org_login = ?
217
+ AND team_database_id = ?
218
+ """,
219
+ [org_login, team_database_id],
220
+ )
221
+ if row is None:
222
+ return None
223
+ return int(row[0]), str(row[1])
224
+
225
+ @lru_cache
226
+ def scim_group_id_for_team_external_group(
227
+ self, org_login: str, external_group_name: str
228
+ ) -> str | None:
229
+ rows = self._find_all_objects(
230
+ f"""
231
+ SELECT DISTINCT esg.id
232
+ FROM {self.schema}.enterprise_scim_groups esg
233
+ JOIN {self.schema}.enterprise_organizations eo
234
+ ON eo.enterprise_node_id = esg.enterprise_node_id
235
+ WHERE eo.login = ?
236
+ AND esg.display_name = ?
237
+ """,
238
+ [org_login, external_group_name],
239
+ )
240
+ if not rows or len(rows) != 1:
241
+ return None
242
+ return str(rows[0][0])
243
+
208
244
  @lru_cache
209
245
  def external_identity_id_for_guid(
210
246
  self, guid: str, environment_slug: str
@@ -61,12 +61,14 @@ def preproc(ctx: PreProcContext):
61
61
  "repo_roles": "repo_roles",
62
62
  "users": "users",
63
63
  "teams": "teams",
64
+ "team_external_groups": "team_external_groups",
64
65
  "team_members": "team_members",
65
66
  "saml_provider": "saml_provider",
66
67
  "external_identities": "external_identities",
67
68
  "applications": "applications",
68
69
  "enterprise": "enterprise",
69
70
  "enterprise_organizations": "enterprise_organizations",
71
+ "enterprise_scim_groups": "enterprise_scim_groups",
70
72
  "enterprise_runner_groups": "enterprise_runner_groups",
71
73
  "enterprise_runner_group_organizations": "enterprise_runner_group_organizations",
72
74
  "enterprise_runner_group_memberships": "enterprise_runner_group_memberships",
@@ -62,7 +62,7 @@ from .scim_user import (
62
62
  ScimUser,
63
63
  )
64
64
  from .secret_scanning_alert import SecretScanningAlert
65
- from .team import Team
65
+ from .team import Team, TeamExternalGroup
66
66
  from .team_member import TeamMember
67
67
  from .team_role import TeamRole
68
68
  from .user import User
@@ -78,6 +78,7 @@ __all__ = [
78
78
  "ActionPermission",
79
79
  "User",
80
80
  "Team",
81
+ "TeamExternalGroup",
81
82
  "TeamRole",
82
83
  "TeamMember",
83
84
  "Repository",
@@ -15,7 +15,7 @@ from openhound_github.main import app
15
15
  @dataclass
16
16
  class GHTeamProperties(GHNodeProperties):
17
17
  """Team-specific properties and accordion panel queries.
18
-
18
+
19
19
  Attributes:
20
20
  collected: Collected/generated by OpenHound
21
21
  github_team_id: The raw GitHub team node ID.
@@ -23,6 +23,8 @@ class GHTeamProperties(GHNodeProperties):
23
23
  description: The team's description.
24
24
  privacy: The team's privacy level (e.g., `visible`, `secret`).
25
25
  type: The team type, such as `enterprise` for projected enterprise teams.
26
+ external_group_id: GitHub's org-scoped external IdP group identifier.
27
+ external_group_name: The external IdP group name reported by GitHub.
26
28
  environment_name: The name of the environment (GitHub organization).
27
29
  query_first_degree_members: Query for first degree members.
28
30
  query_unrolled_members: Query for unrolled members.
@@ -40,6 +42,8 @@ class GHTeamProperties(GHNodeProperties):
40
42
  description: str | None = None
41
43
  privacy: str | None = None
42
44
  type: str | None = None
45
+ external_group_id: int | None = None
46
+ external_group_name: str | None = None
43
47
  environment_name: str | None = None
44
48
 
45
49
  query_first_degree_members: str | None = None
@@ -74,6 +78,16 @@ class ParentTeam(BaseModel):
74
78
  id: str
75
79
 
76
80
 
81
+ class TeamExternalGroup(BaseModel):
82
+ """Raw mapping between an org team and its linked external IdP group."""
83
+
84
+ org_login: str
85
+ team_database_id: int
86
+ external_group_id: int
87
+ external_group_name: str
88
+ external_group_updated_at: str | None = None
89
+
90
+
77
91
  @app.asset(
78
92
  node=NodeDef(
79
93
  kind=nk.TEAM,
@@ -89,6 +103,13 @@ class ParentTeam(BaseModel):
89
103
  description="Team is a child of parent team",
90
104
  traversable=False,
91
105
  ),
106
+ EdgeDef(
107
+ start=nk.SCIM_GROUP,
108
+ end=nk.TEAM,
109
+ kind=ek.SCIM_PROVISIONED,
110
+ description="SCIM group is provisioned as team",
111
+ traversable=True,
112
+ ),
92
113
  ],
93
114
  )
94
115
  class Team(BaseAsset):
@@ -120,9 +141,16 @@ class Team(BaseAsset):
120
141
  """The ID from a GraphQL API response is the same as a regular node_id"""
121
142
  return self.id
122
143
 
144
+ @property
145
+ def external_group(self) -> tuple[int, str] | None:
146
+ if self.database_id is None:
147
+ return None
148
+ return self._lookup.external_group_for_team(self.org_login, self.database_id)
149
+
123
150
  @property
124
151
  def as_node(self) -> GHNode:
125
152
  tid = self.node_id
153
+ external_group = self.external_group
126
154
  return GHNode(
127
155
  kinds=[nk.TEAM],
128
156
  properties=GHTeamProperties(
@@ -132,6 +160,8 @@ class Team(BaseAsset):
132
160
  slug=self.slug,
133
161
  description=self.description,
134
162
  privacy=self.privacy,
163
+ external_group_id=external_group[0] if external_group else None,
164
+ external_group_name=external_group[1] if external_group else None,
135
165
  environment_name=self.org_login,
136
166
  environmentid=self.org_node_id,
137
167
  query_first_degree_members=f"MATCH p=(:GH_User)-[:GH_HasRole]->(t:GH_TeamRole)-[:GH_MemberOf]->(:GH_Team {{node_id:'{tid}'}}) RETURN p",
@@ -176,6 +206,19 @@ class Team(BaseAsset):
176
206
  properties=EdgeProperties(traversable=True),
177
207
  )
178
208
 
209
+ external_group = self.external_group
210
+ if external_group:
211
+ scim_group_id = self._lookup.scim_group_id_for_team_external_group(
212
+ self.org_login, external_group[1]
213
+ )
214
+ if scim_group_id:
215
+ yield Edge(
216
+ kind=ek.SCIM_PROVISIONED,
217
+ start=EdgePath(value=scim_group_id, match_by="id"),
218
+ end=EdgePath(value=self.node_id, match_by="id"),
219
+ properties=EdgeProperties(traversable=True),
220
+ )
221
+
179
222
  # yield from self._branch_edges
180
223
  yield from self._bypass_pull_request_allowances_edges
181
224
  yield from self._bypass_push_allowances_edges
@@ -74,6 +74,7 @@ from openhound_github.models import (
74
74
  SelectedOrgSecret,
75
75
  SelectedOrgVariable,
76
76
  Team,
77
+ TeamExternalGroup,
77
78
  TeamMember,
78
79
  TeamRole,
79
80
  User,
@@ -111,6 +112,7 @@ class SourceContext:
111
112
  cache_lock: Lock = field(default_factory=Lock)
112
113
  organizations_cache: dict[str, dict[str, Any]] = field(default_factory=dict)
113
114
  app_cache: dict[str, dict[str, Any]] = field(default_factory=dict)
115
+ team_rest_cache: dict[str, list[dict[str, Any]]] = field(default_factory=dict)
114
116
  actions_permissions_cache: dict[str, dict[str, Any]] = field(default_factory=dict)
115
117
  runner_permissions_cache: dict[str, dict[str, Any]] = field(default_factory=dict)
116
118
  workflow_permissions_cache: dict[str, dict[str, Any]] = field(default_factory=dict)
@@ -222,6 +224,183 @@ def _workflow_permissions(
222
224
  )
223
225
 
224
226
 
227
+ def _rest_teams_for_org(
228
+ ctx: SourceContext, client: RESTClient, org_name: str
229
+ ) -> list[dict[str, Any]]:
230
+ if org_name not in ctx.team_rest_cache:
231
+ with ctx.cache_lock:
232
+ if org_name not in ctx.team_rest_cache:
233
+ ctx.team_rest_cache[org_name] = [
234
+ team
235
+ for page in client.paginate(
236
+ f"/orgs/{org_name}/teams", params={"per_page": 100}
237
+ )
238
+ for team in page
239
+ ]
240
+ return ctx.team_rest_cache[org_name]
241
+
242
+
243
+ def _external_group_skip_reason(exception: BaseException) -> str | None:
244
+ if not isinstance(exception, requests.HTTPError) or exception.response is None:
245
+ return None
246
+
247
+ status_code = exception.response.status_code
248
+ if status_code in (401, 403):
249
+ return "the configured credentials do not have Members organization permission at write level"
250
+ if status_code == 404:
251
+ return "the GitHub scope does not expose external groups"
252
+ return None
253
+
254
+
255
+ def _external_group_failure_is_terminal(exception: BaseException) -> bool:
256
+ if not isinstance(exception, requests.HTTPError) or exception.response is None:
257
+ return False
258
+ return exception.response.status_code in (401, 403)
259
+
260
+
261
+ def _team_cannot_be_externally_managed(exception: BaseException) -> bool:
262
+ if not isinstance(exception, requests.HTTPError) or exception.response is None:
263
+ return False
264
+ if exception.response.status_code != 400:
265
+ return False
266
+
267
+ try:
268
+ message = str(exception.response.json().get("message", "")).casefold()
269
+ except ValueError:
270
+ return False
271
+ return "cannot be externally managed" in message and "explicit members" in message
272
+
273
+
274
+ def _log_org_external_group_failure(
275
+ resource: str,
276
+ org_name: str,
277
+ exception: BaseException,
278
+ *,
279
+ group_id: int | str | None = None,
280
+ ) -> None:
281
+ skip_reason = _external_group_skip_reason(exception)
282
+ if skip_reason:
283
+ logger.warning(
284
+ "Skipping %s for organization '%s': %s",
285
+ resource,
286
+ org_name,
287
+ skip_reason,
288
+ extra={"resource": resource, "phase": "resource_iteration"},
289
+ )
290
+ return
291
+
292
+ group_context = f" external group '{group_id}'" if group_id is not None else ""
293
+ logger.error(
294
+ "Error in resource '%s' processing organization '%s'%s: %s",
295
+ resource,
296
+ org_name,
297
+ group_context,
298
+ exception,
299
+ extra={"resource": resource, "phase": "resource_iteration"},
300
+ )
301
+
302
+
303
+ def _team_database_id(team_id: Any) -> int | None:
304
+ try:
305
+ return int(team_id)
306
+ except (TypeError, ValueError):
307
+ return None
308
+
309
+
310
+ def _team_external_group_row(
311
+ org_name: str,
312
+ team_id: Any,
313
+ group_id: Any,
314
+ group_name: Any,
315
+ updated_at: Any,
316
+ ) -> dict[str, Any] | None:
317
+ team_database_id = _team_database_id(team_id)
318
+ if group_id is None or not group_name:
319
+ return None
320
+ if team_database_id is None:
321
+ return None
322
+ try:
323
+ return {
324
+ "org_login": org_name,
325
+ "team_database_id": team_database_id,
326
+ "external_group_id": int(group_id),
327
+ "external_group_name": str(group_name),
328
+ "external_group_updated_at": updated_at,
329
+ }
330
+ except (TypeError, ValueError):
331
+ return None
332
+
333
+
334
+ def _team_external_groups_by_group(
335
+ client: RESTClient,
336
+ org_name: str,
337
+ groups: list[dict[str, Any]],
338
+ allowed_team_database_ids: set[int],
339
+ ) -> Iterator[dict[str, Any]]:
340
+ for group in groups:
341
+ group_id = group.get("group_id")
342
+ try:
343
+ response = client.get(f"/orgs/{org_name}/external-group/{group_id}")
344
+ response.raise_for_status()
345
+ group_details = response.json()
346
+ except Exception as e:
347
+ _log_org_external_group_failure(
348
+ "team_external_groups",
349
+ org_name,
350
+ e,
351
+ group_id=group_id,
352
+ )
353
+ if _external_group_failure_is_terminal(e):
354
+ return
355
+ continue
356
+
357
+ group_name = group_details.get("group_name") or group.get("group_name")
358
+ updated_at = group_details.get("updated_at") or group.get("updated_at")
359
+ for team in group_details.get("teams") or []:
360
+ team_database_id = _team_database_id(team.get("team_id"))
361
+ if team_database_id not in allowed_team_database_ids:
362
+ continue
363
+ row = _team_external_group_row(
364
+ org_name,
365
+ team_database_id,
366
+ group_id,
367
+ group_name,
368
+ updated_at,
369
+ )
370
+ if row:
371
+ yield row
372
+
373
+
374
+ def _team_external_groups_by_team(
375
+ client: RESTClient, org_name: str, teams: list[dict[str, Any]]
376
+ ) -> Iterator[dict[str, Any]]:
377
+ for team in teams:
378
+ try:
379
+ response = client.get(
380
+ f"/orgs/{org_name}/teams/{_encode_path_segment(str(team['slug']))}/external-groups"
381
+ )
382
+ response.raise_for_status()
383
+ group_details = response.json()
384
+ except Exception as e:
385
+ if _team_cannot_be_externally_managed(e):
386
+ continue
387
+ _log_org_external_group_failure("team_external_groups", org_name, e)
388
+ if _external_group_failure_is_terminal(e):
389
+ return
390
+ continue
391
+
392
+ for group in group_details.get("groups") or []:
393
+ row = _team_external_group_row(
394
+ org_name,
395
+ team.get("id"),
396
+ group.get("group_id"),
397
+ group.get("group_name"),
398
+ group.get("updated_at"),
399
+ )
400
+ if row:
401
+ yield row
402
+
403
+
225
404
  def _repo_permission_role(repo: dict[str, Any]) -> str:
226
405
  role_name = repo.get("role_name")
227
406
  if role_name:
@@ -574,12 +753,9 @@ def projected_enterprise_teams(ctx: SourceContext):
574
753
  org_name = org.org_name
575
754
  client = org.client
576
755
  try:
577
- for page in client.paginate(
578
- f"/orgs/{org_name}/teams", params={"per_page": 100}
579
- ):
580
- for team in page:
581
- if str(team.get("slug", "")).startswith("ent:") and team.get("node_id"):
582
- yield {**team, "org_login": org_name}
756
+ for team in _rest_teams_for_org(ctx, client, org_name):
757
+ if str(team.get("slug", "")).startswith("ent:") and team.get("node_id"):
758
+ yield {**team, "org_login": org_name}
583
759
  except Exception as e:
584
760
  logger.error(
585
761
  f"Error in resource 'projected_enterprise_teams' processing organization '{org_name}': {e}",
@@ -588,6 +764,58 @@ def projected_enterprise_teams(ctx: SourceContext):
588
764
  continue
589
765
 
590
766
 
767
+ @app.resource(
768
+ name="team_external_groups",
769
+ columns=TeamExternalGroup,
770
+ parallelized=True,
771
+ )
772
+ def team_external_groups(ctx: SourceContext):
773
+ """Collect external IdP group mappings for normal organization teams."""
774
+
775
+ for org in ctx.organizations:
776
+ org_name = org.org_name
777
+ client = org.client
778
+ try:
779
+ groups = [
780
+ group
781
+ for page in client.paginate(
782
+ f"/orgs/{org_name}/external-groups",
783
+ params={"per_page": 100},
784
+ data_selector="groups",
785
+ )
786
+ for group in page
787
+ if group.get("group_id") is not None
788
+ ]
789
+ if not groups:
790
+ continue
791
+
792
+ teams = [
793
+ team
794
+ for team in _rest_teams_for_org(ctx, client, org_name)
795
+ if team.get("id") is not None
796
+ and team.get("slug")
797
+ and not str(team["slug"]).startswith("ent:")
798
+ ]
799
+ team_database_ids = {
800
+ team_database_id
801
+ for team in teams
802
+ if (team_database_id := _team_database_id(team["id"])) is not None
803
+ }
804
+
805
+ if len(groups) <= len(teams):
806
+ yield from _team_external_groups_by_group(
807
+ client,
808
+ org_name,
809
+ groups,
810
+ team_database_ids,
811
+ )
812
+ else:
813
+ yield from _team_external_groups_by_team(client, org_name, teams)
814
+ except Exception as e:
815
+ _log_org_external_group_failure("team_external_groups", org_name, e)
816
+ continue
817
+
818
+
591
819
  @app.transformer(name="team_roles", columns=TeamRole, parallelized=True)
592
820
  def team_roles(team: Team):
593
821
  """Yield the two built-in team roles (members and maintainers) for a team.
@@ -2061,6 +2289,7 @@ def organization_resources(ctx: SourceContext):
2061
2289
  personal_access_tokens_resource = personal_access_tokens(ctx)
2062
2290
 
2063
2291
  teams_resource = teams(ctx)
2292
+ team_external_groups_resource = team_external_groups(ctx)
2064
2293
  repositories_graphql_resource = repositories_graphql(ctx)
2065
2294
  app_installs_resource = app_installations(ctx)
2066
2295
  runner_groups_resource = runner_groups(ctx)
@@ -2090,6 +2319,7 @@ def organization_resources(ctx: SourceContext):
2090
2319
  repos_resource | repository_secrets(ctx),
2091
2320
  repos_resource | repository_variables(ctx),
2092
2321
  teams_resource,
2322
+ team_external_groups_resource,
2093
2323
  projected_enterprise_teams_resource,
2094
2324
  org_scim_organizations_resource,
2095
2325
  teams_resource | team_members(ctx),
@@ -156,6 +156,7 @@ class SourceContext:
156
156
  cache_lock: Lock = field(default_factory=Lock)
157
157
  organizations_cache: dict[str, dict[str, Any]] = field(default_factory=dict)
158
158
  app_cache: dict[str, dict[str, Any]] = field(default_factory=dict)
159
+ team_rest_cache: dict[str, list[dict[str, Any]]] = field(default_factory=dict)
159
160
  actions_permissions_cache: dict[str, dict[str, Any]] = field(default_factory=dict)
160
161
  runner_permissions_cache: dict[str, dict[str, Any]] = field(default_factory=dict)
161
162
  workflow_permissions_cache: dict[str, dict[str, Any]] = field(default_factory=dict)