openhound-github 0.18.0__tar.gz → 0.19.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.
- {openhound_github-0.18.0 → openhound_github-0.19.0}/PKG-INFO +17 -1
- {openhound_github-0.18.0 → openhound_github-0.19.0}/README.md +16 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/nodes/GH_AppInstallation.md +1 -1
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/lookup.py +10 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/models/app_installation.py +10 -2
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/resources/enterprise.py +29 -3
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/resources/organization.py +84 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/source.py +1 -0
- openhound_github-0.19.0/tests/test_app_installation_repo_access.py +130 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/tests/test_classic_personal_access_tokens.py +73 -9
- {openhound_github-0.18.0 → openhound_github-0.19.0}/.github/CODE_OF_CONDUCT.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/.github/CONTRIBUTING.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/.github/GOVERNANCE.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/.github/GitHub-COC-Header.png +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/.github/GitHub-CONTRIB-Header.png +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/.github/GitHub-GOV-Header.png +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/.github/GitHub-Header.png +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/.github/GitHub-LIC-Header.png +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/.github/GitHub-SEC-Header.png +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/.github/SECURITY.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/.github/SO-Dark.svg +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/.github/SO-FOSS-Dark.svg +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/.github/SO-FOSS-Light.svg +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/.github/SO-Light.svg +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/.github/workflows/publish.yml +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/.github/workflows/release-on-merge.yml +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/.github/workflows/validate-branch.yml +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/.gitignore +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/.gitmodules +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/.pre-commit-config.yaml +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/LICENSE.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_AddAssignee.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_AddCollaborator.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_AddLabel.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_AddMember.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_AddedDeployKey.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_AdminTo.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_ApprovesDeploymentTo.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_AssignedTo.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_AuthorizedForOrganization.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_BypassBranchProtection.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_BypassPullRequestAllowances.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_CallsWorkflow.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_CanAccess.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_CanAccessSecret.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_CanAssumeIdentity.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_CanCreateBranch.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_CanCreateEnvironment.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_CanCreateInternalRepositories.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_CanCreatePrivateRepositories.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_CanCreatePublicRepositories.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_CanCreateRepositories.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_CanCreateRepositoryWithRunnerAccess.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_CanDeployToEnvironment.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_CanEditEnvironment.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_CanEditProtection.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_CanInterceptJob.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_CanPwnRequest.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_CanReadSecret.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_CanReadSecretScanningAlert.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_CanRequestOIDCTokenFor.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_CanUseRunner.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_CanWriteBranch.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_CloseDiscussion.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_CloseIssue.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_ClosePullRequest.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_Contains.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_ConvertIssuesToDiscussions.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_CreateDiscussionCategory.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_CreateEnterpriseOrganizations.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_CreateRepository.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_CreateSoloMergeQueueEntry.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_CreateTag.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_CreateTeam.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_DeleteAlertsCodeScanning.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_DeleteDiscussion.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_DeleteDiscussionComment.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_DeleteIssue.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_DeleteTag.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_DependsOn.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_DeploysTo.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_EditCategoryOnDiscussion.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_EditDiscussionCategory.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_EditDiscussionComment.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_EditEnterpriseCustomPropertiesForOrganizations.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_EditRepoAnnouncementBanners.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_EditRepoCustomPropertiesValues.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_EditRepoMetadata.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_EditRepoProtections.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_HasBaseRole.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_HasExternalIdentity.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_HasMember.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_HasPersonalAccessToken.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_HasPersonalAccessTokenRequest.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_HasRole.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_HasRunner.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_HasSamlIdentityProvider.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_HasSecret.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_HasVariable.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_InheritedFrom.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_InstalledAs.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_InviteMember.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_IsEligibleFor.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_JumpMergeQueue.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_ManageDeployKeys.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_ManageDiscussionBadges.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_ManageEnterpriseAdmins.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_ManageEnterpriseIdentityProvider.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_ManageEnterpriseMembers.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_ManageEnterpriseOrganizationAdmins.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_ManageEnterpriseOrganizations.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_ManageEnterpriseReferrals.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_ManageEnterpriseTeams.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_ManageOrganizationWebhooks.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_ManageRepoSecurityProducts.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_ManageSecurityProducts.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_ManageSettingsMergeTypes.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_ManageSettingsPages.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_ManageSettingsProjects.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_ManageSettingsWiki.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_ManageTopics.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_ManageWebhooks.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_MapsToUser.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_MarkAsDuplicate.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_MatchesEnvironmentPolicy.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_MemberOf.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_OrgBypassCodeScanningDismissalRequests.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_OrgBypassSecretScanningClosureRequests.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_OrgReviewAndManageSecretScanningBypassRequests.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_OrgReviewAndManageSecretScanningClosureRequests.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_Owns.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_ProtectedBy.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_PushProtectedBranch.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_ReadCodeScanning.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_ReadEnterpriseAuditLog.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_ReadEnterpriseDomainVerification.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_ReadEnterpriseMembers.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_ReadEnterpriseOrgProjects.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_ReadEnterpriseOrganizationAdmin.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_ReadOrganizationActionsUsageMetrics.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_ReadOrganizationCustomOrgRole.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_ReadOrganizationCustomRepoRole.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_ReadRepoContents.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_RemoveAssignee.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_RemoveLabel.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_ReopenDiscussion.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_ReopenIssue.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_ReopenPullRequest.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_RequestPrReview.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_ResolveDependabotAlerts.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_ResolveSecretScanningAlerts.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_RestrictionsCanPush.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_RunOrgMigration.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_RunsOn.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_SetEnterpriseInteractionLimits.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_SetInteractionLimits.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_SetIssueType.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_SetMilestone.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_SetSocialPreview.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_SyncedTo.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_ToggleDiscussionAnswer.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_ToggleDiscussionCommentMinimize.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_TransferRepository.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_UsesSecret.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_UsesVariable.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_ValidToken.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_ViewDependabotAlerts.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_ViewEnterpriseActionsUsageMetrics.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_ViewEnterpriseBilling.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_ViewEnterpriseSecretScanningAlerts.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_ViewSecretScanningAlerts.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_WriteCodeScanning.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_WriteEnterpriseActionsPolicies.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_WriteEnterpriseBilling.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_WriteEnterprisePersonalAccessTokenPolicies.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_WriteEnterpriseSso.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_WriteEnterpriseTeamMembers.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_WriteOrganizationActionsSecrets.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_WriteOrganizationActionsSettings.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_WriteOrganizationActionsVariables.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_WriteOrganizationCustomOrgRole.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_WriteOrganizationCustomRepoRole.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_WriteOrganizationNetworkConfigurations.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_WriteRepoContents.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_WriteRepoPullRequests.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/nodes/GH_App.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/nodes/GH_Branch.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/nodes/GH_BranchProtectionRule.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/nodes/GH_ClassicPersonalAccessToken.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/nodes/GH_DeployKey.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/nodes/GH_Enterprise.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/nodes/GH_EnterpriseManagedUser.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/nodes/GH_EnterpriseRole.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/nodes/GH_EnterpriseRunner.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/nodes/GH_EnterpriseRunnerGroup.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/nodes/GH_EnterpriseTeam.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/nodes/GH_Environment.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/nodes/GH_EnvironmentBranchPolicy.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/nodes/GH_EnvironmentSecret.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/nodes/GH_EnvironmentVariable.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/nodes/GH_ExternalIdentity.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/nodes/GH_OrgRole.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/nodes/GH_OrgRunner.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/nodes/GH_OrgRunnerGroup.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/nodes/GH_OrgSecret.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/nodes/GH_OrgVariable.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/nodes/GH_Organization.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/nodes/GH_PersonalAccessToken.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/nodes/GH_PersonalAccessTokenRequest.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/nodes/GH_RepoRole.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/nodes/GH_RepoRunner.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/nodes/GH_RepoSecret.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/nodes/GH_RepoVariable.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/nodes/GH_Repository.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/nodes/GH_Runner.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/nodes/GH_RunnerGroup.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/nodes/GH_SamlIdentityProvider.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/nodes/GH_Secret.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/nodes/GH_SecretScanningAlert.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/nodes/GH_Team.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/nodes/GH_TeamRole.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/nodes/GH_User.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/nodes/GH_Variable.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/nodes/GH_Workflow.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/nodes/GH_WorkflowJob.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/nodes/GH_WorkflowStep.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/docs/og-docs.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/privilege_zone_rules/t0-all-repo-admin-role.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/privilege_zone_rules/t0-app-installations-all-repos.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/privilege_zone_rules/t0-apps-all-repos.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/privilege_zone_rules/t0-enterprise-owners-role.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/privilege_zone_rules/t0-external-identities-owners.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/privilege_zone_rules/t0-organizations.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/privilege_zone_rules/t0-owner-users.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/privilege_zone_rules/t0-owners-role.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/privilege_zone_rules/t0-pats-all-repos.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/privilege_zone_rules/t0-privilege-escalation-roles.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/privilege_zone_rules/t0-privilege-escalation-users.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/privilege_zone_rules/t0-saml-identity-providers.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/saved_searches/README.md +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/saved_searches/actions-sha-pinning-not-required.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/saved_searches/active-leaked-secrets.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/saved_searches/advanced-security-disabled-new-repos.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/saved_searches/all-actions-allowed.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/saved_searches/app-installations-all-repos.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/saved_searches/branch-protection-admins-not-enforced.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/saved_searches/branch-protection-deletions-allowed.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/saved_searches/branch-protection-force-pushes.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/saved_searches/branch-protection-no-code-owner-reviews.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/saved_searches/branch-protection-no-pr-reviews.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/saved_searches/branch-protection-no-status-checks.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/saved_searches/branch-protection-self-approval.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/saved_searches/branch-protection-stale-reviews.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/saved_searches/bypass-pr-requirements.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/saved_searches/dangerous-branch-perms.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/saved_searches/default-repository-permissions.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/saved_searches/demo-sso-to-cloud-round-trip.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/saved_searches/dependabot-alerts-disabled-new-repos.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/saved_searches/dependabot-updates-disabled-new-repos.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/saved_searches/dependency-graph-disabled-new-repos.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/saved_searches/environments-admin-bypass.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/saved_searches/expired-pats.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/saved_searches/external-identities-without-scim.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/saved_searches/github-to-azure-identity.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/saved_searches/global-repo-perms.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/saved_searches/hybrid-identities.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/saved_searches/members-can-change-repo-visibility.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/saved_searches/members-can-create-pages.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/saved_searches/members-can-create-public-repos.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/saved_searches/members-can-delete-repos.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/saved_searches/members-can-fork-private-repos.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/saved_searches/members-can-invite-outside-collaborators.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/saved_searches/org-owners.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/saved_searches/orgs-without-2fa.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/saved_searches/pats-all-repo-access.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/saved_searches/pending-pat-requests.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/saved_searches/private-repos-forking-allowed.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/saved_searches/privileged-custom-org-roles.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/saved_searches/privileged-hybrid-identities.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/saved_searches/public-repos.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/saved_searches/push-protection-disabled-new-repos.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/saved_searches/push-to-protected-branches.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/saved_searches/repos-secret-scanning-disabled.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/saved_searches/repos-vulnerable-to-workflow-secret-exfil.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/saved_searches/repository-workflows.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/saved_searches/saml-configuration.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/saved_searches/secret-scanning-alerts.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/saved_searches/secret-scanning-disabled-new-repos.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/saved_searches/secrets-reachable-by-user.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/saved_searches/self-hosted-runners-can-intercept-broad-token-jobs.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/saved_searches/shared-self-hosted-runners-can-intercept-secret-bearing-jobs.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/saved_searches/team-membership-admin.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/saved_searches/team-structure.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/saved_searches/unprotected-branches.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/saved_searches/unprotected-default-branch-with-workflow.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/saved_searches/unprotected-default-branches.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/saved_searches/web-commit-signoff-not-required.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/saved_searches/workflow-jobs-interceptable-by-self-hosted-runners.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/saved_searches/workflow-jobs-with-broad-token-write-permissions.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/saved_searches/workflow-jobs-with-id-token-write-on-self-hosted-runners.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/saved_searches/workflow-jobs-with-id-token-write.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/saved_searches/workflow-jobs-with-observed-oidc-auth-steps.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/extension/schema.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/justfile +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/pyproject.toml +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/scripts/generate_gh_description_docs.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/main.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/__init__.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/auth.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/extension.yaml +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/github_rest_client.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/github_retry.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/graph.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/graphql.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/helpers.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/kinds/edges.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/kinds/nodes.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/main.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/models/__init__.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/models/actions_permission.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/models/branch.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/models/branch_pr_bypass_allowance.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/models/branch_protection_rule.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/models/branch_push_allowance.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/models/classic_personal_access_token.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/models/deploy_key.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/models/enterprise.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/models/enterprise_admin.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/models/enterprise_helpers.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/models/enterprise_managed_user.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/models/enterprise_member.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/models/enterprise_organization.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/models/enterprise_role.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/models/enterprise_role_team.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/models/enterprise_role_user.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/models/enterprise_team.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/models/enterprise_team_member.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/models/enterprise_team_organization.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/models/enterprise_team_role.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/models/enterprise_user.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/models/env_secret.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/models/env_variable.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/models/environment.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/models/environment_branch_policy.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/models/external_identity.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/models/org.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/models/org_role.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/models/org_role_member.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/models/org_role_team.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/models/org_secret.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/models/org_variable.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/models/permissions.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/models/personal_access_token.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/models/personal_access_token_access.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/models/personal_access_token_request.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/models/projected_enterprise_team.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/models/repo_role_assignment.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/models/repository.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/models/repository_role.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/models/repository_secret.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/models/repository_variable.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/models/runner.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/models/saml_assertion_consumer_service.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/models/saml_helpers.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/models/saml_issuer.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/models/saml_provider.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/models/saml_service_provider.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/models/scim_user.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/models/secret_scanning_alert.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/models/team.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/models/team_member.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/models/team_role.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/models/user.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/models/workflow.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/models/workflow_job.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/models/workflow_reference.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/models/workflow_step.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/resources/__init__.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/runner_ids.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/transforms.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/tests/test_app_auth.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/tests/test_branch_collection_gate.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/tests/test_branch_protection_traversability.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/tests/test_credential_permission_models.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/tests/test_data/api/actions-permissions.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/tests/test_data/api/actionsecrets.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/tests/test_data/api/app.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/tests/test_data/api/appinstalls.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/tests/test_data/api/branch-policies.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/tests/test_data/api/branch-prot-rules.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/tests/test_data/api/branches.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/tests/test_data/api/custom-roles.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/tests/test_data/api/environments.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/tests/test_data/api/org-pat-request.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/tests/test_data/api/org-pat.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/tests/test_data/api/org-role-teams.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/tests/test_data/api/org-role-users.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/tests/test_data/api/org-roles.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/tests/test_data/api/org.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/tests/test_data/api/pat-repositories.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/tests/test_data/api/repo-collaborators.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/tests/test_data/api/repo-teams.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/tests/test_data/api/repositories.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/tests/test_data/api/scimusers.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/tests/test_data/api/secrets.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/tests/test_data/api/secretscanningalert.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/tests/test_data/api/selected-org-secrets.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/tests/test_data/api/variables.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/tests/test_data/api/workflows.json +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/tests/test_deploy_key_models.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/tests/test_deploy_key_resources.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/tests/test_description_docs.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/tests/test_enterprise_capabilities.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/tests/test_enterprise_organization.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/tests/test_enterprise_resources.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/tests/test_environment_model.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/tests/test_environment_resources.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/tests/test_environment_reviewer_lookup.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/tests/test_error_resilience.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/tests/test_github_app_retry.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/tests/test_github_rest_client.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/tests/test_github_retry.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/tests/test_helpers.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/tests/test_lookup.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/tests/test_org_role_model.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/tests/test_org_scim_resources.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/tests/test_org_secret_models.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/tests/test_preproc.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/tests/test_repository_rulesets.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/tests/test_runner_ids.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/tests/test_runner_models.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/tests/test_runner_resources.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/tests/test_saml_helpers.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/tests/test_saml_models.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/tests/test_scim_models.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/tests/test_source_endpoints.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/tests/test_source_org_canonicalization.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/tests/test_team_external_groups.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/tests/test_variable_models.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/tests/test_workflow_interception_path.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/tests/test_workflow_model.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/tests/test_workflow_resources.py +0 -0
- {openhound_github-0.18.0 → openhound_github-0.19.0}/uv.lock +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: openhound-github
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.19.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
|
|
@@ -84,6 +84,22 @@ The collector runs successfully with the documented read-only permission set. So
|
|
|
84
84
|
|
|
85
85
|
If these optional permissions are not granted, OpenHound skips the affected resources and continues collecting the rest of the GitHub environment.
|
|
86
86
|
|
|
87
|
+
### Selected GitHub App installation repositories
|
|
88
|
+
|
|
89
|
+
For organization installations limited to selected repositories, the collector
|
|
90
|
+
uses the enterprise installation's read-only organization-installation
|
|
91
|
+
repositories API to create exact `GH_CanAccess` edges. Grant the enterprise
|
|
92
|
+
installation **Enterprise organization installations: read** or **Enterprise
|
|
93
|
+
organization installation repositories: read**. Without either permission,
|
|
94
|
+
selected-repository edges are skipped; installations set to `all` continue to
|
|
95
|
+
use the collected organization repository inventory.
|
|
96
|
+
|
|
97
|
+
Installation discovery still uses each organization's API and requires
|
|
98
|
+
**Organization administration: read** on that organization's credential. The
|
|
99
|
+
enterprise permission alone does not discover installations.
|
|
100
|
+
The selected-repository lookup runs one installation at a time and stops for
|
|
101
|
+
the rest of a collection if GitHub rate-limits it after retries.
|
|
102
|
+
|
|
87
103
|
### Classic personal access token inventory
|
|
88
104
|
|
|
89
105
|
With GitHub Enterprise Cloud credentials, the collector uses the enterprise
|
|
@@ -73,6 +73,22 @@ The collector runs successfully with the documented read-only permission set. So
|
|
|
73
73
|
|
|
74
74
|
If these optional permissions are not granted, OpenHound skips the affected resources and continues collecting the rest of the GitHub environment.
|
|
75
75
|
|
|
76
|
+
### Selected GitHub App installation repositories
|
|
77
|
+
|
|
78
|
+
For organization installations limited to selected repositories, the collector
|
|
79
|
+
uses the enterprise installation's read-only organization-installation
|
|
80
|
+
repositories API to create exact `GH_CanAccess` edges. Grant the enterprise
|
|
81
|
+
installation **Enterprise organization installations: read** or **Enterprise
|
|
82
|
+
organization installation repositories: read**. Without either permission,
|
|
83
|
+
selected-repository edges are skipped; installations set to `all` continue to
|
|
84
|
+
use the collected organization repository inventory.
|
|
85
|
+
|
|
86
|
+
Installation discovery still uses each organization's API and requires
|
|
87
|
+
**Organization administration: read** on that organization's credential. The
|
|
88
|
+
enterprise permission alone does not discover installations.
|
|
89
|
+
The selected-repository lookup runs one installation at a time and stops for
|
|
90
|
+
the rest of a collection if GitHub rate-limits it after retries.
|
|
91
|
+
|
|
76
92
|
### Classic personal access token inventory
|
|
77
93
|
|
|
78
94
|
With GitHub Enterprise Cloud credentials, the collector uses the enterprise
|
{openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/nodes/GH_AppInstallation.md
RENAMED
|
@@ -6,7 +6,7 @@ Represents a GitHub App installed on an organization. App installations have spe
|
|
|
6
6
|
|
|
7
7
|
Unlike fine-grained personal access tokens, GitHub does not expose separate organization and repository permission buckets for app installations, so this property remains a single flat permission list.
|
|
8
8
|
|
|
9
|
-
Each installation is linked to its parent GH_App via a GH_InstalledAs edge. For installations with `repository_selection` set to `all`, GH_CanAccess edges are created to every repository in the organization. For installations with `repository_selection` set to `selected`,
|
|
9
|
+
Each installation is linked to its parent GH_App via a GH_InstalledAs edge. For installations with `repository_selection` set to `all`, GH_CanAccess edges are created to every collected repository in the organization. For installations with `repository_selection` set to `selected`, the collector uses the enterprise organization-installation repositories API to enumerate the granted repositories when the enterprise installation has `Enterprise organization installations: read` or `Enterprise organization installation repositories: read`. If that permission is unavailable, selected repository edges are skipped.
|
|
10
10
|
|
|
11
11
|
## Properties
|
|
12
12
|
|
|
@@ -597,6 +597,16 @@ class GithubLookup(LookupManager):
|
|
|
597
597
|
[org_login],
|
|
598
598
|
)
|
|
599
599
|
|
|
600
|
+
@lru_cache
|
|
601
|
+
def repository_node_id_for_database_id(
|
|
602
|
+
self, database_id: int, org_login: str
|
|
603
|
+
) -> str | None:
|
|
604
|
+
"""Resolve a repository node by database ID within its organization."""
|
|
605
|
+
return self._find_single_object(
|
|
606
|
+
f"SELECT node_id FROM {self.schema}.repositories WHERE database_id = ? AND lower(org_login) = lower(?) LIMIT 1",
|
|
607
|
+
[database_id, org_login],
|
|
608
|
+
)
|
|
609
|
+
|
|
600
610
|
@lru_cache
|
|
601
611
|
def private_repository_node_ids(self):
|
|
602
612
|
return self._find_all_objects(
|
{openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/models/app_installation.py
RENAMED
|
@@ -320,7 +320,9 @@ class AppInstallationRepoAccess(BaseAsset):
|
|
|
320
320
|
"""One record from `app_installation_repo_access` → GH_CanAccess edge. No node."""
|
|
321
321
|
|
|
322
322
|
installation_node_id: str
|
|
323
|
-
|
|
323
|
+
repository_database_id: int
|
|
324
|
+
repo_full_name: str | None = None
|
|
325
|
+
org_login: str
|
|
324
326
|
|
|
325
327
|
@property
|
|
326
328
|
def as_node(self):
|
|
@@ -328,11 +330,17 @@ class AppInstallationRepoAccess(BaseAsset):
|
|
|
328
330
|
|
|
329
331
|
@property
|
|
330
332
|
def edges(self) -> list[Edge]:
|
|
333
|
+
"""Link the installation to a collected repository when it resolves."""
|
|
334
|
+
repo_node_id = self._lookup.repository_node_id_for_database_id(
|
|
335
|
+
self.repository_database_id, self.org_login
|
|
336
|
+
)
|
|
337
|
+
if not repo_node_id:
|
|
338
|
+
return []
|
|
331
339
|
return [
|
|
332
340
|
Edge(
|
|
333
341
|
kind=ek.CAN_ACCESS,
|
|
334
342
|
start=EdgePath(value=self.installation_node_id, match_by="id"),
|
|
335
|
-
end=EdgePath(value=
|
|
343
|
+
end=EdgePath(value=repo_node_id, match_by="id"),
|
|
336
344
|
properties=EdgeProperties(traversable=False),
|
|
337
345
|
)
|
|
338
346
|
]
|
{openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/resources/enterprise.py
RENAMED
|
@@ -73,6 +73,14 @@ _CREDENTIAL_EXPORT_TIMEOUT_SECONDS = 300
|
|
|
73
73
|
_CREDENTIAL_EXPORT_REUSE_SECONDS = 24 * 60 * 60
|
|
74
74
|
|
|
75
75
|
|
|
76
|
+
class _CredentialExportFailed(ValueError):
|
|
77
|
+
"""The export job reported a terminal failed status."""
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class _CredentialExportNotFound(requests.HTTPError):
|
|
81
|
+
"""The export-status endpoint no longer recognizes a saved export ID."""
|
|
82
|
+
|
|
83
|
+
|
|
76
84
|
@dataclass
|
|
77
85
|
class SourceContext:
|
|
78
86
|
"""Shared context for GitHub API access."""
|
|
@@ -215,8 +223,13 @@ def _download_enterprise_credential_inventory(
|
|
|
215
223
|
deadline = time.monotonic() + _CREDENTIAL_EXPORT_TIMEOUT_SECONDS
|
|
216
224
|
export_path = f"{path}/{export_id}"
|
|
217
225
|
while True:
|
|
218
|
-
|
|
219
|
-
|
|
226
|
+
try:
|
|
227
|
+
response = client.get(export_path, headers=headers, allow_redirects=False)
|
|
228
|
+
response.raise_for_status()
|
|
229
|
+
except requests.HTTPError as exc:
|
|
230
|
+
if exc.response is not None and exc.response.status_code == 404:
|
|
231
|
+
raise _CredentialExportNotFound(response=exc.response) from exc
|
|
232
|
+
raise
|
|
220
233
|
if response.status_code == 302:
|
|
221
234
|
download_url = response.headers.get("Location")
|
|
222
235
|
parsed_url = urlparse(download_url or "")
|
|
@@ -259,6 +272,10 @@ def _download_enterprise_credential_inventory(
|
|
|
259
272
|
polled_metadata = response.json()
|
|
260
273
|
export_metadata.update(polled_metadata)
|
|
261
274
|
status = polled_metadata.get("status")
|
|
275
|
+
if status == "failed":
|
|
276
|
+
raise _CredentialExportFailed(
|
|
277
|
+
"Credential export did not complete: 'failed'"
|
|
278
|
+
)
|
|
262
279
|
if status not in {"queued", "started", "in_progress", "processing", "pending"}:
|
|
263
280
|
raise ValueError(f"Credential export did not complete: {status!r}")
|
|
264
281
|
if time.monotonic() >= deadline:
|
|
@@ -316,7 +333,7 @@ def enterprise_credential_inventory(enterprise_data: Enterprise, ctx: SourceCont
|
|
|
316
333
|
}
|
|
317
334
|
return
|
|
318
335
|
except requests.HTTPError as exc:
|
|
319
|
-
if
|
|
336
|
+
if not isinstance(exc, _CredentialExportNotFound):
|
|
320
337
|
logger.warning(
|
|
321
338
|
"Skipping credential inventory for enterprise '%s': prior export %s unavailable (HTTP %s)",
|
|
322
339
|
ctx.enterprise_name,
|
|
@@ -326,11 +343,20 @@ def enterprise_credential_inventory(enterprise_data: Enterprise, ctx: SourceCont
|
|
|
326
343
|
else "unknown",
|
|
327
344
|
)
|
|
328
345
|
return
|
|
346
|
+
state.pop("last_export_id", None)
|
|
329
347
|
logger.info(
|
|
330
348
|
"Prior credential export %s is no longer available for enterprise '%s'; creating a new export",
|
|
331
349
|
previous_id,
|
|
332
350
|
ctx.enterprise_name,
|
|
333
351
|
)
|
|
352
|
+
except _CredentialExportFailed:
|
|
353
|
+
state.pop("last_export_id", None)
|
|
354
|
+
logger.warning(
|
|
355
|
+
"Skipping credential inventory for enterprise '%s': prior export %s failed",
|
|
356
|
+
ctx.enterprise_name,
|
|
357
|
+
previous_id,
|
|
358
|
+
)
|
|
359
|
+
return
|
|
334
360
|
except (
|
|
335
361
|
requests.RequestException,
|
|
336
362
|
ValueError,
|
{openhound_github-0.18.0 → openhound_github-0.19.0}/src/openhound_github/resources/organization.py
RENAMED
|
@@ -23,6 +23,10 @@ from openhound_github.graphql import (
|
|
|
23
23
|
TEAM_MEMBERS_OVERFLOW_QUERY,
|
|
24
24
|
TEAMS_QUERY,
|
|
25
25
|
)
|
|
26
|
+
from openhound_github.github_retry import (
|
|
27
|
+
is_primary_rate_limit_response,
|
|
28
|
+
is_secondary_rate_limit_response,
|
|
29
|
+
)
|
|
26
30
|
from openhound_github.helpers import (
|
|
27
31
|
AdaptiveGraphQLPageError,
|
|
28
32
|
DEFAULT_GITHUB_REST_API_URL,
|
|
@@ -36,6 +40,7 @@ from openhound_github.models import (
|
|
|
36
40
|
ActionPermission,
|
|
37
41
|
App,
|
|
38
42
|
AppInstallation,
|
|
43
|
+
AppInstallationRepoAccess,
|
|
39
44
|
BaseRepoRole,
|
|
40
45
|
Branch,
|
|
41
46
|
BranchProtectionRule,
|
|
@@ -117,6 +122,7 @@ class SourceContext:
|
|
|
117
122
|
deployment_type: str = "unknown"
|
|
118
123
|
ghes_version: str | None = None
|
|
119
124
|
enterprise_version_header: str | None = None
|
|
125
|
+
selected_installation_repo_access_stopped: bool = False
|
|
120
126
|
cache_lock: Lock = field(default_factory=Lock)
|
|
121
127
|
organizations_cache: dict[str, dict[str, Any]] = field(default_factory=dict)
|
|
122
128
|
app_cache: dict[str, dict[str, Any]] = field(default_factory=dict)
|
|
@@ -655,6 +661,82 @@ def app_installations(ctx: SourceContext):
|
|
|
655
661
|
continue
|
|
656
662
|
|
|
657
663
|
|
|
664
|
+
@app.transformer(
|
|
665
|
+
name="app_installation_repo_access",
|
|
666
|
+
columns=AppInstallationRepoAccess,
|
|
667
|
+
parallelized=False,
|
|
668
|
+
)
|
|
669
|
+
def app_installation_repo_access(app_install: AppInstallation, ctx: SourceContext):
|
|
670
|
+
"""List the repositories granted to a selected organization installation."""
|
|
671
|
+
if (
|
|
672
|
+
app_install.repository_selection != "selected"
|
|
673
|
+
or not ctx.client
|
|
674
|
+
or not ctx.enterprise_name
|
|
675
|
+
or ctx.deployment_type == "ghes"
|
|
676
|
+
or ctx.selected_installation_repo_access_stopped
|
|
677
|
+
):
|
|
678
|
+
return
|
|
679
|
+
|
|
680
|
+
path = (
|
|
681
|
+
f"/enterprises/{ctx.enterprise_name}/apps/organizations/"
|
|
682
|
+
f"{app_install.org_login}/installations/{app_install.id}/repositories"
|
|
683
|
+
)
|
|
684
|
+
try:
|
|
685
|
+
# Read every page before yielding so a failed page cannot create partial access.
|
|
686
|
+
repositories = [
|
|
687
|
+
repository
|
|
688
|
+
for page in ctx.client.paginate(
|
|
689
|
+
path,
|
|
690
|
+
params={"per_page": 100},
|
|
691
|
+
headers={"X-GitHub-Api-Version": "2026-03-10"},
|
|
692
|
+
)
|
|
693
|
+
for repository in page
|
|
694
|
+
]
|
|
695
|
+
except requests.HTTPError as exc:
|
|
696
|
+
response = exc.response
|
|
697
|
+
if response is not None and (
|
|
698
|
+
response.status_code == 429
|
|
699
|
+
or is_primary_rate_limit_response(response)
|
|
700
|
+
or is_secondary_rate_limit_response(response)
|
|
701
|
+
or (response.status_code == 403 and response.headers.get("Retry-After"))
|
|
702
|
+
):
|
|
703
|
+
ctx.selected_installation_repo_access_stopped = True
|
|
704
|
+
logger.warning(
|
|
705
|
+
"GitHub rate-limited selected app installation repository access; "
|
|
706
|
+
"skipping remaining installations in this collection"
|
|
707
|
+
)
|
|
708
|
+
return
|
|
709
|
+
logger.warning(
|
|
710
|
+
"Skipping repository access for app installation %s in organization '%s': %s",
|
|
711
|
+
app_install.id,
|
|
712
|
+
app_install.org_login,
|
|
713
|
+
exc,
|
|
714
|
+
)
|
|
715
|
+
return
|
|
716
|
+
except Exception as exc:
|
|
717
|
+
logger.warning(
|
|
718
|
+
"Skipping repository access for app installation %s in organization '%s': %s",
|
|
719
|
+
app_install.id,
|
|
720
|
+
app_install.org_login,
|
|
721
|
+
exc,
|
|
722
|
+
)
|
|
723
|
+
return
|
|
724
|
+
|
|
725
|
+
for repository in repositories:
|
|
726
|
+
if repository.get("id") is None:
|
|
727
|
+
logger.warning(
|
|
728
|
+
"Skipping repository without an id for app installation %s",
|
|
729
|
+
app_install.id,
|
|
730
|
+
)
|
|
731
|
+
continue
|
|
732
|
+
yield {
|
|
733
|
+
"installation_node_id": app_install.node_id,
|
|
734
|
+
"repository_database_id": repository["id"],
|
|
735
|
+
"repo_full_name": repository.get("full_name"),
|
|
736
|
+
"org_login": app_install.org_login,
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
|
|
658
740
|
@app.transformer(name="applications", columns=App, parallelized=True)
|
|
659
741
|
def applications(app_install: AppInstallation, ctx: SourceContext):
|
|
660
742
|
"""Fetch full GitHub App details for an installed app.
|
|
@@ -2368,6 +2450,7 @@ def org_scim_organizations(org: Organization, ctx: SourceContext):
|
|
|
2368
2450
|
|
|
2369
2451
|
|
|
2370
2452
|
def organization_resources(ctx: SourceContext):
|
|
2453
|
+
"""Assemble organization resources, including selected installation access."""
|
|
2371
2454
|
org_resource = organizations(ctx)
|
|
2372
2455
|
roles_resource = org_roles(ctx)
|
|
2373
2456
|
repo_roles_base = RepositoryRoleCache(ctx)
|
|
@@ -2397,6 +2480,7 @@ def organization_resources(ctx: SourceContext):
|
|
|
2397
2480
|
org_resource | roles_resource | org_role_teams(ctx),
|
|
2398
2481
|
org_resource | roles_resource | org_role_members(ctx),
|
|
2399
2482
|
app_installs_resource,
|
|
2483
|
+
app_installs_resource | app_installation_repo_access(ctx),
|
|
2400
2484
|
app_installs_resource | applications(ctx),
|
|
2401
2485
|
users(ctx),
|
|
2402
2486
|
actions_permissions(ctx),
|
|
@@ -170,6 +170,7 @@ class SourceContext:
|
|
|
170
170
|
deployment_type: str = "unknown"
|
|
171
171
|
ghes_version: str | None = None
|
|
172
172
|
enterprise_version_header: str | None = None
|
|
173
|
+
selected_installation_repo_access_stopped: bool = False
|
|
173
174
|
cache_lock: Lock = field(default_factory=Lock)
|
|
174
175
|
organizations_cache: dict[str, dict[str, Any]] = field(default_factory=dict)
|
|
175
176
|
app_cache: dict[str, dict[str, Any]] = field(default_factory=dict)
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
from types import SimpleNamespace
|
|
2
|
+
from unittest.mock import MagicMock
|
|
3
|
+
|
|
4
|
+
import duckdb
|
|
5
|
+
from requests import HTTPError, Response
|
|
6
|
+
|
|
7
|
+
from openhound_github.lookup import GithubLookup
|
|
8
|
+
from openhound_github.models.app_installation import AppInstallationRepoAccess
|
|
9
|
+
from openhound_github.resources.organization import (
|
|
10
|
+
SourceContext,
|
|
11
|
+
app_installation_repo_access,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _installation(selection="selected"):
|
|
16
|
+
"""Build a minimal installation for repository access tests."""
|
|
17
|
+
return SimpleNamespace(
|
|
18
|
+
id=42,
|
|
19
|
+
node_id="GH_AppInstallation_42",
|
|
20
|
+
org_login="example-org",
|
|
21
|
+
repository_selection=selection,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def test_selected_installation_lists_all_pages_with_enterprise_client():
|
|
26
|
+
"""Collect every page of repositories granted to a selected installation."""
|
|
27
|
+
client = MagicMock()
|
|
28
|
+
client.paginate.return_value = [
|
|
29
|
+
[{"id": 101, "name": "one", "full_name": "example-org/one"}],
|
|
30
|
+
[{"id": 102, "name": "two", "full_name": "example-org/two"}],
|
|
31
|
+
]
|
|
32
|
+
ctx = SourceContext(
|
|
33
|
+
client=client, enterprise_name="enterprise", deployment_type="ghec"
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
rows = list(app_installation_repo_access.__wrapped__(_installation(), ctx))
|
|
37
|
+
|
|
38
|
+
assert rows == [
|
|
39
|
+
{
|
|
40
|
+
"installation_node_id": "GH_AppInstallation_42",
|
|
41
|
+
"repository_database_id": 101,
|
|
42
|
+
"repo_full_name": "example-org/one",
|
|
43
|
+
"org_login": "example-org",
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"installation_node_id": "GH_AppInstallation_42",
|
|
47
|
+
"repository_database_id": 102,
|
|
48
|
+
"repo_full_name": "example-org/two",
|
|
49
|
+
"org_login": "example-org",
|
|
50
|
+
},
|
|
51
|
+
]
|
|
52
|
+
client.paginate.assert_called_once_with(
|
|
53
|
+
"/enterprises/enterprise/apps/organizations/example-org/"
|
|
54
|
+
"installations/42/repositories",
|
|
55
|
+
params={"per_page": 100},
|
|
56
|
+
headers={"X-GitHub-Api-Version": "2026-03-10"},
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def test_all_repositories_do_not_need_extra_request():
|
|
61
|
+
"""Skip the repository lookup when an installation already selects all."""
|
|
62
|
+
client = MagicMock()
|
|
63
|
+
ctx = SourceContext(
|
|
64
|
+
client=client, enterprise_name="enterprise", deployment_type="ghec"
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
assert list(app_installation_repo_access.__wrapped__(_installation("all"), ctx)) == []
|
|
68
|
+
client.paginate.assert_not_called()
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def test_failed_later_page_does_not_emit_partial_access(caplog):
|
|
72
|
+
"""Discard earlier pages if a later page fails."""
|
|
73
|
+
client = MagicMock()
|
|
74
|
+
|
|
75
|
+
def pages(*args, **kwargs):
|
|
76
|
+
"""Yield one page before simulating a pagination failure."""
|
|
77
|
+
yield [{"id": 101, "full_name": "example-org/one"}]
|
|
78
|
+
raise PermissionError("403 Forbidden")
|
|
79
|
+
|
|
80
|
+
client.paginate.side_effect = pages
|
|
81
|
+
ctx = SourceContext(
|
|
82
|
+
client=client, enterprise_name="enterprise", deployment_type="ghec"
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
assert list(app_installation_repo_access.__wrapped__(_installation(), ctx)) == []
|
|
86
|
+
assert "Skipping repository access" in caplog.text
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def test_rate_limit_stops_remaining_selected_installation_requests(caplog):
|
|
90
|
+
"""Stop further selected-installation lookups after a rate limit."""
|
|
91
|
+
response = Response()
|
|
92
|
+
response.status_code = 429
|
|
93
|
+
error = HTTPError("429 Too Many Requests", response=response)
|
|
94
|
+
client = MagicMock()
|
|
95
|
+
client.paginate.side_effect = error
|
|
96
|
+
ctx = SourceContext(
|
|
97
|
+
client=client, enterprise_name="enterprise", deployment_type="ghec"
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
assert list(app_installation_repo_access.__wrapped__(_installation(), ctx)) == []
|
|
101
|
+
assert list(app_installation_repo_access.__wrapped__(_installation(), ctx)) == []
|
|
102
|
+
|
|
103
|
+
client.paginate.assert_called_once()
|
|
104
|
+
assert ctx.selected_installation_repo_access_stopped is True
|
|
105
|
+
assert "skipping remaining installations" in caplog.text
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def test_selected_repository_id_resolves_to_access_edge():
|
|
109
|
+
"""Resolve repository access within the installation organization."""
|
|
110
|
+
connection = duckdb.connect(":memory:")
|
|
111
|
+
connection.execute("CREATE SCHEMA github")
|
|
112
|
+
connection.execute(
|
|
113
|
+
"CREATE TABLE github.repositories (node_id VARCHAR, database_id BIGINT, org_login VARCHAR)"
|
|
114
|
+
)
|
|
115
|
+
connection.execute(
|
|
116
|
+
"INSERT INTO github.repositories VALUES ('R_1', 101, 'example-org'), ('R_2', 101, 'other-org')"
|
|
117
|
+
)
|
|
118
|
+
access = AppInstallationRepoAccess(
|
|
119
|
+
installation_node_id="GH_AppInstallation_42",
|
|
120
|
+
repository_database_id=101,
|
|
121
|
+
org_login="example-org",
|
|
122
|
+
)
|
|
123
|
+
access._lookup = GithubLookup(connection)
|
|
124
|
+
|
|
125
|
+
edges = access.edges
|
|
126
|
+
|
|
127
|
+
assert len(edges) == 1
|
|
128
|
+
assert edges[0].start.value == "GH_AppInstallation_42"
|
|
129
|
+
assert edges[0].end.value == "R_1"
|
|
130
|
+
assert edges[0].properties.traversable is False
|
{openhound_github-0.18.0 → openhound_github-0.19.0}/tests/test_classic_personal_access_tokens.py
RENAMED
|
@@ -444,7 +444,10 @@ def test_classic_pat_inventory_resumes_export_after_download_failure(
|
|
|
444
444
|
app_client.get.assert_not_called()
|
|
445
445
|
|
|
446
446
|
|
|
447
|
-
|
|
447
|
+
@pytest.mark.parametrize("status_code", [404, 503])
|
|
448
|
+
def test_classic_pat_cached_export_error_does_not_log_download_url(
|
|
449
|
+
monkeypatch, caplog, status_code
|
|
450
|
+
):
|
|
448
451
|
"""Keep signed download URLs out of cached-export error logs."""
|
|
449
452
|
state = {
|
|
450
453
|
"last_export_id": "prior-1",
|
|
@@ -460,7 +463,7 @@ def test_classic_pat_cached_export_error_does_not_log_download_url(monkeypatch,
|
|
|
460
463
|
signed_url = "https://example.test/export.csv?secret=signed-download-token"
|
|
461
464
|
client.get.return_value = Response(302, headers={"Location": signed_url})
|
|
462
465
|
failed_response = requests.Response()
|
|
463
|
-
failed_response.status_code =
|
|
466
|
+
failed_response.status_code = status_code
|
|
464
467
|
failed_response.url = signed_url
|
|
465
468
|
failed_response._content = b""
|
|
466
469
|
monkeypatch.setattr(
|
|
@@ -477,8 +480,9 @@ def test_classic_pat_cached_export_error_does_not_log_download_url(monkeypatch,
|
|
|
477
480
|
)
|
|
478
481
|
== []
|
|
479
482
|
)
|
|
480
|
-
assert "HTTP
|
|
483
|
+
assert f"HTTP {status_code}" in caplog.text
|
|
481
484
|
assert "signed-download-token" not in caplog.text
|
|
485
|
+
assert state["last_export_id"] == "prior-1"
|
|
482
486
|
client.post.assert_not_called()
|
|
483
487
|
|
|
484
488
|
|
|
@@ -596,13 +600,14 @@ def test_classic_pat_inventory_reuses_recent_export_before_creating(monkeypatch)
|
|
|
596
600
|
|
|
597
601
|
|
|
598
602
|
def test_classic_pat_inventory_creates_export_when_recent_one_is_gone(monkeypatch):
|
|
603
|
+
state = {
|
|
604
|
+
"last_export_id": "prior-1",
|
|
605
|
+
"last_export_enterprise": "enterprise",
|
|
606
|
+
"last_export_downloaded_at": 1000,
|
|
607
|
+
}
|
|
599
608
|
monkeypatch.setattr(
|
|
600
609
|
"openhound_github.resources.enterprise.dlt.current.resource_state",
|
|
601
|
-
lambda _:
|
|
602
|
-
"last_export_id": "prior-1",
|
|
603
|
-
"last_export_enterprise": "enterprise",
|
|
604
|
-
"last_export_downloaded_at": 1000,
|
|
605
|
-
},
|
|
610
|
+
lambda _: state,
|
|
606
611
|
)
|
|
607
612
|
monkeypatch.setattr("openhound_github.resources.enterprise.time.time", lambda: 1001)
|
|
608
613
|
client = MagicMock()
|
|
@@ -623,9 +628,68 @@ def test_classic_pat_inventory_creates_export_when_recent_one_is_gone(monkeypatc
|
|
|
623
628
|
enterprise_credential_inventory.__wrapped__(SimpleNamespace(id="E_1"), ctx)
|
|
624
629
|
)
|
|
625
630
|
assert inventories[0]["export_id"] == "new-1"
|
|
631
|
+
assert state["last_export_id"] == "new-1"
|
|
626
632
|
client.post.assert_called_once()
|
|
627
633
|
|
|
628
634
|
|
|
635
|
+
def test_classic_pat_inventory_discards_missing_prior_export(monkeypatch):
|
|
636
|
+
"""Clear a missing export ID even if creating its replacement fails."""
|
|
637
|
+
state = {
|
|
638
|
+
"last_export_id": "prior-1",
|
|
639
|
+
"last_export_enterprise": "enterprise",
|
|
640
|
+
"last_export_created_at": 1000,
|
|
641
|
+
}
|
|
642
|
+
monkeypatch.setattr(
|
|
643
|
+
"openhound_github.resources.enterprise.dlt.current.resource_state",
|
|
644
|
+
lambda _: state,
|
|
645
|
+
)
|
|
646
|
+
monkeypatch.setattr("openhound_github.resources.enterprise.time.time", lambda: 1001)
|
|
647
|
+
client = MagicMock()
|
|
648
|
+
client.get.return_value = Response(404)
|
|
649
|
+
client.post.return_value = Response(429)
|
|
650
|
+
ctx = SourceContext(
|
|
651
|
+
client=client, enterprise_name="enterprise", deployment_type="ghec"
|
|
652
|
+
)
|
|
653
|
+
|
|
654
|
+
assert (
|
|
655
|
+
list(
|
|
656
|
+
enterprise_credential_inventory.__wrapped__(SimpleNamespace(id="E_1"), ctx)
|
|
657
|
+
)
|
|
658
|
+
== []
|
|
659
|
+
)
|
|
660
|
+
assert "last_export_id" not in state
|
|
661
|
+
client.post.assert_called_once()
|
|
662
|
+
|
|
663
|
+
|
|
664
|
+
@pytest.mark.parametrize("status", ["failed", "unknown"])
|
|
665
|
+
def test_classic_pat_inventory_only_discards_failed_prior_export(monkeypatch, status):
|
|
666
|
+
"""Keep a saved ID for unexpected statuses but discard a failed export."""
|
|
667
|
+
state = {
|
|
668
|
+
"last_export_id": "prior-1",
|
|
669
|
+
"last_export_enterprise": "enterprise",
|
|
670
|
+
"last_export_created_at": 1000,
|
|
671
|
+
}
|
|
672
|
+
monkeypatch.setattr(
|
|
673
|
+
"openhound_github.resources.enterprise.dlt.current.resource_state",
|
|
674
|
+
lambda _: state,
|
|
675
|
+
)
|
|
676
|
+
monkeypatch.setattr("openhound_github.resources.enterprise.time.time", lambda: 1001)
|
|
677
|
+
client = MagicMock()
|
|
678
|
+
client.get.return_value = Response(200, payload={"status": status})
|
|
679
|
+
ctx = SourceContext(
|
|
680
|
+
client=client, enterprise_name="enterprise", deployment_type="ghec"
|
|
681
|
+
)
|
|
682
|
+
|
|
683
|
+
assert (
|
|
684
|
+
list(
|
|
685
|
+
enterprise_credential_inventory.__wrapped__(SimpleNamespace(id="E_1"), ctx)
|
|
686
|
+
)
|
|
687
|
+
== []
|
|
688
|
+
)
|
|
689
|
+
assert state.get("last_export_id") == (None if status == "failed" else "prior-1")
|
|
690
|
+
client.post.assert_not_called()
|
|
691
|
+
|
|
692
|
+
|
|
629
693
|
def test_classic_pat_inventory_reuses_pat_created_export_with_pat(monkeypatch):
|
|
630
694
|
state = {}
|
|
631
695
|
monkeypatch.setattr(
|
|
@@ -747,7 +811,7 @@ def test_classic_pat_failed_export_produces_no_partial_inventory(caplog):
|
|
|
747
811
|
)
|
|
748
812
|
== []
|
|
749
813
|
)
|
|
750
|
-
assert "
|
|
814
|
+
assert "CredentialExportFailed" in caplog.text
|
|
751
815
|
client.post.assert_called_once()
|
|
752
816
|
|
|
753
817
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_AddCollaborator.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_ApprovesDeploymentTo.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openhound_github-0.18.0 → openhound_github-0.19.0}/descriptions/edges/GH_BypassBranchProtection.md
RENAMED
|
File without changes
|
|
File without changes
|