openhound-github 0.6.1__tar.gz → 0.6.2__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.6.1 → openhound_github-0.6.2}/PKG-INFO +1 -1
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/auth.py +15 -2
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/helpers.py +31 -3
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/models/repository.py +4 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/resources/organization.py +23 -2
- {openhound_github-0.6.1 → openhound_github-0.6.2}/tests/test_app_auth.py +20 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/tests/test_github_app_retry.py +17 -0
- openhound_github-0.6.2/tests/test_helpers.py +102 -0
- openhound_github-0.6.2/tests/test_repository_rulesets.py +241 -0
- openhound_github-0.6.1/tests/test_repository_rulesets.py +0 -137
- {openhound_github-0.6.1 → openhound_github-0.6.2}/.github/CODE_OF_CONDUCT.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/.github/CONTRIBUTING.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/.github/GOVERNANCE.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/.github/GitHub-COC-Header.png +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/.github/GitHub-CONTRIB-Header.png +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/.github/GitHub-GOV-Header.png +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/.github/GitHub-Header.png +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/.github/GitHub-LIC-Header.png +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/.github/GitHub-SEC-Header.png +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/.github/SECURITY.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/.github/SO-Dark.svg +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/.github/SO-FOSS-Dark.svg +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/.github/SO-FOSS-Light.svg +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/.github/SO-Light.svg +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/.github/workflows/publish.yml +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/.github/workflows/release-on-merge.yml +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/.github/workflows/validate-branch.yml +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/.gitignore +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/.gitmodules +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/.pre-commit-config.yaml +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/LICENSE.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/README.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_AddAssignee.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_AddCollaborator.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_AddLabel.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_AddMember.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_AdminTo.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_ApprovesDeploymentTo.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_AssignedTo.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_BypassBranchProtection.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_BypassPullRequestAllowances.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_CallsWorkflow.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_CanAccess.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_CanAssumeIdentity.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_CanCreateBranch.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_CanCreateEnvironment.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_CanCreateRepositoryWithRunnerAccess.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_CanDeployToEnvironment.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_CanEditEnvironment.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_CanEditProtection.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_CanPwnRequest.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_CanReadSecretScanningAlert.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_CanUseRunner.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_CanWriteBranch.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_CloseDiscussion.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_CloseIssue.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_ClosePullRequest.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_Contains.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_ConvertIssuesToDiscussions.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_CreateDiscussionCategory.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_CreateRepository.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_CreateSoloMergeQueueEntry.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_CreateTag.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_CreateTeam.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_DeleteAlertsCodeScanning.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_DeleteDiscussion.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_DeleteDiscussionComment.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_DeleteIssue.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_DeleteTag.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_DependsOn.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_DeploysTo.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_EditCategoryOnDiscussion.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_EditDiscussionCategory.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_EditDiscussionComment.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_EditRepoAnnouncementBanners.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_EditRepoCustomPropertiesValues.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_EditRepoMetadata.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_EditRepoProtections.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_HasBaseRole.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_HasBranch.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_HasEnvironment.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_HasExternalIdentity.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_HasJob.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_HasMember.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_HasPersonalAccessToken.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_HasPersonalAccessTokenRequest.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_HasRole.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_HasRunner.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_HasSamlIdentityProvider.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_HasSecret.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_HasStep.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_HasVariable.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_HasWorkflow.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_InheritedFrom.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_InstalledAs.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_InviteMember.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_IsEligibleFor.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_JumpMergeQueue.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_ManageDeployKeys.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_ManageDiscussionBadges.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_ManageOrganizationWebhooks.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_ManageRepoSecurityProducts.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_ManageSecurityProducts.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_ManageSettingsMergeTypes.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_ManageSettingsPages.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_ManageSettingsProjects.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_ManageSettingsWiki.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_ManageTopics.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_ManageWebhooks.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_MapsToUser.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_MarkAsDuplicate.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_MatchesEnvironmentPolicy.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_MemberOf.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_OrgBypassCodeScanningDismissalRequests.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_OrgBypassSecretScanningClosureRequests.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_OrgReviewAndManageSecretScanningBypassRequests.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_OrgReviewAndManageSecretScanningClosureRequests.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_Owns.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_ProtectedBy.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_PushProtectedBranch.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_ReadCodeScanning.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_ReadOrganizationActionsUsageMetrics.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_ReadOrganizationCustomOrgRole.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_ReadOrganizationCustomRepoRole.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_ReadRepoContents.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_RemoveAssignee.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_RemoveLabel.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_ReopenDiscussion.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_ReopenIssue.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_ReopenPullRequest.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_RequestPrReview.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_ResolveDependabotAlerts.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_ResolveSecretScanningAlerts.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_RestrictionsCanPush.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_RunOrgMigration.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_SetInteractionLimits.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_SetIssueType.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_SetMilestone.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_SetSocialPreview.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_SyncedTo.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_ToggleDiscussionAnswer.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_ToggleDiscussionCommentMinimize.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_TransferRepository.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_UsesSecret.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_UsesVariable.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_ValidToken.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_ViewDependabotAlerts.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_ViewSecretScanningAlerts.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_WriteCodeScanning.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_WriteOrganizationActionsSecrets.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_WriteOrganizationActionsSettings.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_WriteOrganizationActionsVariables.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_WriteOrganizationCustomOrgRole.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_WriteOrganizationCustomRepoRole.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_WriteOrganizationNetworkConfigurations.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_WriteRepoContents.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/edges/GH_WriteRepoPullRequests.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/nodes/GH_App.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/nodes/GH_AppInstallation.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/nodes/GH_Branch.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/nodes/GH_BranchProtectionRule.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/nodes/GH_EnterpriseRunner.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/nodes/GH_EnterpriseRunnerGroup.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/nodes/GH_Environment.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/nodes/GH_EnvironmentBranchPolicy.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/nodes/GH_EnvironmentSecret.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/nodes/GH_EnvironmentVariable.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/nodes/GH_ExternalIdentity.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/nodes/GH_OrgRole.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/nodes/GH_OrgRunner.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/nodes/GH_OrgRunnerGroup.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/nodes/GH_OrgSecret.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/nodes/GH_OrgVariable.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/nodes/GH_Organization.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/nodes/GH_PersonalAccessToken.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/nodes/GH_PersonalAccessTokenRequest.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/nodes/GH_RepoRole.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/nodes/GH_RepoRunner.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/nodes/GH_RepoSecret.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/nodes/GH_RepoVariable.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/nodes/GH_Repository.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/nodes/GH_SamlIdentityProvider.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/nodes/GH_SecretScanningAlert.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/nodes/GH_Team.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/nodes/GH_TeamRole.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/nodes/GH_User.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/nodes/GH_Workflow.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/nodes/GH_WorkflowJob.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/descriptions/nodes/GH_WorkflowStep.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/docs/og-docs.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/extension/privilege_zone_rules/t0-all-repo-admin-role.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/extension/privilege_zone_rules/t0-app-installations-all-repos.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/extension/privilege_zone_rules/t0-apps-all-repos.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/extension/privilege_zone_rules/t0-external-identities-owners.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/extension/privilege_zone_rules/t0-organizations.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/extension/privilege_zone_rules/t0-owner-users.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/extension/privilege_zone_rules/t0-owners-role.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/extension/privilege_zone_rules/t0-pats-all-repos.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/extension/privilege_zone_rules/t0-privilege-escalation-roles.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/extension/privilege_zone_rules/t0-privilege-escalation-users.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/extension/privilege_zone_rules/t0-saml-identity-providers.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/extension/saved_searches/README.md +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/extension/saved_searches/actions-sha-pinning-not-required.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/extension/saved_searches/active-leaked-secrets.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/extension/saved_searches/advanced-security-disabled-new-repos.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/extension/saved_searches/all-actions-allowed.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/extension/saved_searches/app-installations-all-repos.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/extension/saved_searches/branch-protection-admins-not-enforced.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/extension/saved_searches/branch-protection-deletions-allowed.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/extension/saved_searches/branch-protection-force-pushes.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/extension/saved_searches/branch-protection-no-code-owner-reviews.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/extension/saved_searches/branch-protection-no-pr-reviews.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/extension/saved_searches/branch-protection-no-status-checks.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/extension/saved_searches/branch-protection-self-approval.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/extension/saved_searches/branch-protection-stale-reviews.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/extension/saved_searches/bypass-pr-requirements.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/extension/saved_searches/dangerous-branch-perms.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/extension/saved_searches/default-repository-permissions.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/extension/saved_searches/demo-sso-to-cloud-round-trip.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/extension/saved_searches/dependabot-alerts-disabled-new-repos.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/extension/saved_searches/dependabot-updates-disabled-new-repos.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/extension/saved_searches/dependency-graph-disabled-new-repos.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/extension/saved_searches/environments-admin-bypass.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/extension/saved_searches/expired-pats.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/extension/saved_searches/external-identities-without-scim.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/extension/saved_searches/github-to-azure-identity.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/extension/saved_searches/global-repo-perms.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/extension/saved_searches/hybrid-identities.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/extension/saved_searches/members-can-change-repo-visibility.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/extension/saved_searches/members-can-create-pages.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/extension/saved_searches/members-can-create-public-repos.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/extension/saved_searches/members-can-delete-repos.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/extension/saved_searches/members-can-fork-private-repos.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/extension/saved_searches/members-can-invite-outside-collaborators.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/extension/saved_searches/org-owners.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/extension/saved_searches/orgs-without-2fa.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/extension/saved_searches/pats-all-repo-access.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/extension/saved_searches/pending-pat-requests.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/extension/saved_searches/private-repos-forking-allowed.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/extension/saved_searches/privileged-custom-org-roles.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/extension/saved_searches/privileged-hybrid-identities.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/extension/saved_searches/public-repos.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/extension/saved_searches/push-protection-disabled-new-repos.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/extension/saved_searches/push-to-protected-branches.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/extension/saved_searches/repos-secret-scanning-disabled.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/extension/saved_searches/repos-vulnerable-to-workflow-secret-exfil.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/extension/saved_searches/repository-workflows.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/extension/saved_searches/saml-configuration.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/extension/saved_searches/secret-scanning-alerts.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/extension/saved_searches/secret-scanning-disabled-new-repos.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/extension/saved_searches/secrets-reachable-by-user.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/extension/saved_searches/team-membership-admin.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/extension/saved_searches/team-structure.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/extension/saved_searches/unprotected-branches.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/extension/saved_searches/unprotected-default-branch-with-workflow.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/extension/saved_searches/unprotected-default-branches.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/extension/saved_searches/web-commit-signoff-not-required.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/extension/schema.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/justfile +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/pyproject.toml +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/main.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/__init__.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/extension.yaml +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/graph.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/graphql.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/kinds/edges.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/kinds/nodes.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/lookup.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/main.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/models/__init__.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/models/actions_permission.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/models/app_installation.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/models/branch.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/models/branch_pr_bypass_allowance.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/models/branch_protection_rule.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/models/branch_push_allowance.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/models/enterprise.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/models/enterprise_admin.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/models/enterprise_helpers.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/models/enterprise_managed_user.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/models/enterprise_member.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/models/enterprise_organization.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/models/enterprise_role.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/models/enterprise_role_team.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/models/enterprise_role_user.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/models/enterprise_team.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/models/enterprise_team_member.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/models/enterprise_team_organization.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/models/enterprise_team_role.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/models/enterprise_user.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/models/env_secret.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/models/env_variable.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/models/environment.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/models/environment_branch_policy.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/models/external_identity.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/models/org.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/models/org_role.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/models/org_role_member.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/models/org_role_team.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/models/org_secret.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/models/org_variable.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/models/personal_access_token.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/models/personal_access_token_access.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/models/personal_access_token_request.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/models/projected_enterprise_team.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/models/repo_role_assignment.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/models/repository_role.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/models/repository_secret.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/models/repository_variable.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/models/runner.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/models/saml_assertion_consumer_service.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/models/saml_helpers.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/models/saml_issuer.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/models/saml_provider.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/models/saml_service_provider.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/models/scim_user.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/models/secret_scanning_alert.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/models/team.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/models/team_member.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/models/team_role.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/models/user.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/models/workflow.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/models/workflow_job.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/models/workflow_step.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/resources/__init__.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/resources/enterprise.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/runner_ids.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/source.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/transforms.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/tests/test_branch_collection_gate.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/tests/test_branch_protection_traversability.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/tests/test_data/api/actions-permissions.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/tests/test_data/api/actionsecrets.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/tests/test_data/api/app.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/tests/test_data/api/appinstalls.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/tests/test_data/api/branch-policies.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/tests/test_data/api/branch-prot-rules.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/tests/test_data/api/branches.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/tests/test_data/api/custom-roles.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/tests/test_data/api/environments.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/tests/test_data/api/org-pat-request.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/tests/test_data/api/org-pat.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/tests/test_data/api/org-role-teams.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/tests/test_data/api/org-role-users.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/tests/test_data/api/org-roles.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/tests/test_data/api/org.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/tests/test_data/api/pat-repositories.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/tests/test_data/api/repo-collaborators.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/tests/test_data/api/repo-teams.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/tests/test_data/api/repositories.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/tests/test_data/api/scimusers.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/tests/test_data/api/secrets.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/tests/test_data/api/secretscanningalert.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/tests/test_data/api/selected-org-secrets.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/tests/test_data/api/variables.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/tests/test_data/api/workflows.json +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/tests/test_enterprise_capabilities.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/tests/test_enterprise_organization.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/tests/test_enterprise_resources.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/tests/test_environment_model.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/tests/test_environment_resources.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/tests/test_environment_reviewer_lookup.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/tests/test_error_resilience.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/tests/test_external_identity_tenant_matching.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/tests/test_github_rest_client.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/tests/test_github_retry.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/tests/test_org_secret_models.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/tests/test_runner_ids.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/tests/test_runner_models.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/tests/test_runner_resources.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/tests/test_saml_helpers.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/tests/test_saml_models.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/tests/test_scim_models.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/tests/test_variable_models.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/tests/test_workflow_model.py +0 -0
- {openhound_github-0.6.1 → openhound_github-0.6.2}/uv.lock +0 -0
|
@@ -19,11 +19,22 @@ from pydantic import BaseModel
|
|
|
19
19
|
logger = logging.getLogger(__name__)
|
|
20
20
|
|
|
21
21
|
|
|
22
|
-
def _normalized_http_origin(
|
|
22
|
+
def _normalized_http_origin(
|
|
23
|
+
url: str, *, allow_query: bool = False
|
|
24
|
+
) -> tuple[str, str, int | None]:
|
|
23
25
|
parsed = urlparse(url)
|
|
24
26
|
scheme = parsed.scheme.lower()
|
|
25
27
|
if scheme != "https" or not parsed.hostname:
|
|
26
28
|
raise ValueError("GitHub API URI must be an absolute HTTPS URL")
|
|
29
|
+
if (
|
|
30
|
+
parsed.username is not None
|
|
31
|
+
or parsed.password is not None
|
|
32
|
+
or (parsed.query and not allow_query)
|
|
33
|
+
or parsed.fragment
|
|
34
|
+
):
|
|
35
|
+
raise ValueError(
|
|
36
|
+
"GitHub API URI must not contain user-info, query strings, or fragments"
|
|
37
|
+
)
|
|
27
38
|
|
|
28
39
|
port = parsed.port
|
|
29
40
|
if scheme == "https" and port == 443:
|
|
@@ -230,7 +241,9 @@ class GitHubAppInstallationAuth(AuthConfigBase):
|
|
|
230
241
|
def refresh_request(self, request: requests.PreparedRequest) -> bool:
|
|
231
242
|
"""Repair a rejected same-origin request without stampeding token issuance."""
|
|
232
243
|
try:
|
|
233
|
-
request_origin = _normalized_http_origin(
|
|
244
|
+
request_origin = _normalized_http_origin(
|
|
245
|
+
request.url or "", allow_query=True
|
|
246
|
+
)
|
|
234
247
|
except ValueError:
|
|
235
248
|
return False
|
|
236
249
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
import time
|
|
3
3
|
from typing import Optional
|
|
4
|
+
from urllib.parse import urlparse
|
|
4
5
|
|
|
5
6
|
from dlt.common import jsonpath
|
|
6
7
|
from dlt.sources.helpers import requests
|
|
@@ -153,6 +154,25 @@ def _has_graphql_errors(response: requests.Response) -> bool:
|
|
|
153
154
|
return isinstance(response_data, dict) and bool(response_data.get("errors"))
|
|
154
155
|
|
|
155
156
|
|
|
157
|
+
def _has_invalid_json_body(response: requests.Response) -> bool:
|
|
158
|
+
try:
|
|
159
|
+
response.json()
|
|
160
|
+
except ValueError:
|
|
161
|
+
return True
|
|
162
|
+
return False
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def _is_graphql_response(response: requests.Response) -> bool:
|
|
166
|
+
if response.headers.get("x-ratelimit-resource") == "graphql":
|
|
167
|
+
return True
|
|
168
|
+
|
|
169
|
+
request = response.request
|
|
170
|
+
if request is None or not request.url:
|
|
171
|
+
return False
|
|
172
|
+
|
|
173
|
+
return urlparse(request.url).path.rstrip("/").endswith("/graphql")
|
|
174
|
+
|
|
175
|
+
|
|
156
176
|
def github_retry_policy(auth: AuthConfigBase):
|
|
157
177
|
def retry_policy(
|
|
158
178
|
response: Optional[requests.Response], exception: Optional[BaseException]
|
|
@@ -162,12 +182,11 @@ def github_retry_policy(auth: AuthConfigBase):
|
|
|
162
182
|
|
|
163
183
|
headers = response.headers
|
|
164
184
|
now = int(time.time())
|
|
165
|
-
message = _response_message(response).lower()
|
|
166
185
|
|
|
167
186
|
# DLT retries the same prepared request after long Retry-After sleeps.
|
|
168
187
|
if (
|
|
169
188
|
response.status_code == 401
|
|
170
|
-
and "bad credentials" in
|
|
189
|
+
and "bad credentials" in _response_message(response).lower()
|
|
171
190
|
and isinstance(auth, GitHubAppInstallationAuth)
|
|
172
191
|
and response.request is not None
|
|
173
192
|
):
|
|
@@ -180,7 +199,15 @@ def github_retry_policy(auth: AuthConfigBase):
|
|
|
180
199
|
|
|
181
200
|
if (
|
|
182
201
|
response.status_code == 200
|
|
183
|
-
and
|
|
202
|
+
and _is_graphql_response(response)
|
|
203
|
+
and _has_invalid_json_body(response)
|
|
204
|
+
):
|
|
205
|
+
logger.warning("GraphQL response body was not valid JSON, retrying request")
|
|
206
|
+
return True
|
|
207
|
+
|
|
208
|
+
if (
|
|
209
|
+
response.status_code == 200
|
|
210
|
+
and _is_graphql_response(response)
|
|
184
211
|
and _has_graphql_errors(response)
|
|
185
212
|
):
|
|
186
213
|
if headers.get("Retry-After"):
|
|
@@ -199,6 +226,7 @@ def github_retry_policy(auth: AuthConfigBase):
|
|
|
199
226
|
if response.status_code not in (403, 429):
|
|
200
227
|
return False
|
|
201
228
|
|
|
229
|
+
message = _response_message(response).lower()
|
|
202
230
|
if (
|
|
203
231
|
headers.get("x-ratelimit-remaining") == "0"
|
|
204
232
|
or "api rate limit exceeded" in message
|
|
@@ -29,6 +29,7 @@ class GHRepositoryProperties(GHNodeProperties):
|
|
|
29
29
|
disabled: Whether the repository is disabled.
|
|
30
30
|
visibility: The visibility level: `public`, `private`, or `internal`.
|
|
31
31
|
default_branch: The name of the default branch (e.g., `main`).
|
|
32
|
+
size: Repository size in kilobytes as reported by GitHub.
|
|
32
33
|
open_issues_count: Number of open issues.
|
|
33
34
|
allow_forking: Whether forking is allowed.
|
|
34
35
|
web_commit_signoff_required: Whether web-based commits require sign-off.
|
|
@@ -74,6 +75,7 @@ class GHRepositoryProperties(GHNodeProperties):
|
|
|
74
75
|
disabled: bool | None = None
|
|
75
76
|
visibility: str | None = None
|
|
76
77
|
default_branch: str | None = None
|
|
78
|
+
size: int | None = None
|
|
77
79
|
open_issues_count: int | None = None
|
|
78
80
|
allow_forking: bool | None = None
|
|
79
81
|
web_commit_signoff_required: bool | None = None
|
|
@@ -195,6 +197,7 @@ class Repository(BaseAsset):
|
|
|
195
197
|
disabled: bool | None = None
|
|
196
198
|
visibility: str | None = None
|
|
197
199
|
default_branch: str | None = None
|
|
200
|
+
size: int | None = None
|
|
198
201
|
open_issues_count: int | None = None
|
|
199
202
|
allow_forking: bool | None = None
|
|
200
203
|
web_commit_signoff_required: bool | None = None
|
|
@@ -240,6 +243,7 @@ class Repository(BaseAsset):
|
|
|
240
243
|
disabled=self.disabled,
|
|
241
244
|
visibility=self.visibility,
|
|
242
245
|
default_branch=self.default_branch,
|
|
246
|
+
size=self.size,
|
|
243
247
|
open_issues_count=self.open_issues_count,
|
|
244
248
|
allow_forking=self.allow_forking,
|
|
245
249
|
web_commit_signoff_required=self.web_commit_signoff_required,
|
{openhound_github-0.6.1 → openhound_github-0.6.2}/src/openhound_github/resources/organization.py
RENAMED
|
@@ -916,6 +916,8 @@ def repositories_graphql(ctx: SourceContext):
|
|
|
916
916
|
for org in ctx.organizations:
|
|
917
917
|
org_name = org.org_name
|
|
918
918
|
client = org.client
|
|
919
|
+
repository_cursor: str | None = None
|
|
920
|
+
emitted_repositories = 0
|
|
919
921
|
try:
|
|
920
922
|
paginator = GraphQLCursorPaginator(
|
|
921
923
|
page_info_path="data.organization.repositories.pageInfo",
|
|
@@ -939,15 +941,34 @@ def repositories_graphql(ctx: SourceContext):
|
|
|
939
941
|
for repo in repos_page["nodes"]:
|
|
940
942
|
repo_record = {**repo}
|
|
941
943
|
branch_rulesets = repo_record.pop("branchRulesets", None) or {}
|
|
944
|
+
emitted_repositories += 1
|
|
942
945
|
yield {
|
|
943
946
|
**repo_record,
|
|
944
947
|
"branch_ruleset_count": branch_rulesets.get("totalCount"),
|
|
945
948
|
"org_login": org_name,
|
|
946
949
|
}
|
|
950
|
+
|
|
951
|
+
page_info = repos_page.get("pageInfo") or {}
|
|
952
|
+
if isinstance(page_info, dict):
|
|
953
|
+
repository_cursor = page_info.get("endCursor")
|
|
947
954
|
except Exception as e:
|
|
948
955
|
logger.error(
|
|
949
|
-
|
|
950
|
-
|
|
956
|
+
"Error in resource 'repositories_graphql' processing organization '%s' "
|
|
957
|
+
"at repository cursor %r after emitting %d repositories "
|
|
958
|
+
"(%s): %s",
|
|
959
|
+
org_name,
|
|
960
|
+
repository_cursor,
|
|
961
|
+
emitted_repositories,
|
|
962
|
+
type(e).__name__,
|
|
963
|
+
e,
|
|
964
|
+
extra={
|
|
965
|
+
"resource": "repositories_graphql",
|
|
966
|
+
"phase": "resource_iteration",
|
|
967
|
+
"org_name": org_name,
|
|
968
|
+
"repository_cursor": repository_cursor,
|
|
969
|
+
"emitted_repositories": emitted_repositories,
|
|
970
|
+
"error_type": type(e).__name__,
|
|
971
|
+
},
|
|
951
972
|
)
|
|
952
973
|
continue
|
|
953
974
|
|
|
@@ -120,6 +120,26 @@ def test_github_session_rejects_plaintext_api_uri() -> None:
|
|
|
120
120
|
)
|
|
121
121
|
|
|
122
122
|
|
|
123
|
+
@pytest.mark.parametrize(
|
|
124
|
+
"api_uri",
|
|
125
|
+
(
|
|
126
|
+
"https://user:password@ghe.example/api/v3/",
|
|
127
|
+
"https://ghe.example/api/v3/?token=secret",
|
|
128
|
+
"https://ghe.example/api/v3/#fragment",
|
|
129
|
+
),
|
|
130
|
+
)
|
|
131
|
+
def test_github_session_rejects_api_uri_with_unsafe_components(api_uri: str) -> None:
|
|
132
|
+
with pytest.raises(
|
|
133
|
+
ValueError,
|
|
134
|
+
match="must not contain user-info, query strings, or fragments",
|
|
135
|
+
):
|
|
136
|
+
GithubSession(
|
|
137
|
+
jwt_issuer="123456",
|
|
138
|
+
private_key_path="/tmp/github-app.pem",
|
|
139
|
+
api_uri=api_uri,
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
|
|
123
143
|
def test_enterprise_source_reuses_selected_issuer_for_installation_tokens(
|
|
124
144
|
monkeypatch: pytest.MonkeyPatch,
|
|
125
145
|
) -> None:
|
|
@@ -99,6 +99,23 @@ def test_refresh_request_refreshes_rejected_current_token() -> None:
|
|
|
99
99
|
assert installation.token_calls == 1
|
|
100
100
|
|
|
101
101
|
|
|
102
|
+
def test_refresh_request_allows_same_origin_request_query_string() -> None:
|
|
103
|
+
installation = FakeInstallation("new-token")
|
|
104
|
+
auth = GitHubAppInstallationAuth(installation=installation)
|
|
105
|
+
auth.access_token = "old-token"
|
|
106
|
+
auth.expires_at = datetime.now(timezone.utc) + timedelta(hours=1)
|
|
107
|
+
request = prepared_request(
|
|
108
|
+
"old-token",
|
|
109
|
+
url="https://api.github.com/repos/example/repo?page=2",
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
repaired = auth.refresh_request(request)
|
|
113
|
+
|
|
114
|
+
assert repaired is True
|
|
115
|
+
assert request.headers["Authorization"] == "Bearer new-token"
|
|
116
|
+
assert installation.token_calls == 1
|
|
117
|
+
|
|
118
|
+
|
|
102
119
|
def test_refresh_request_reuses_token_refreshed_by_another_request() -> None:
|
|
103
120
|
installation = BlockingFakeInstallation("new-token")
|
|
104
121
|
auth = GitHubAppInstallationAuth(installation=installation)
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import json
|
|
2
|
+
|
|
3
|
+
import requests
|
|
4
|
+
from dlt.sources.helpers.rest_client.auth import BearerTokenAuth
|
|
5
|
+
from dlt.sources.helpers.requests.retry import Client
|
|
6
|
+
from dlt.sources.helpers.requests.session import Session
|
|
7
|
+
|
|
8
|
+
from openhound_github.helpers import github_retry_policy
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def graphql_response(
|
|
12
|
+
*,
|
|
13
|
+
headers: dict[str, str] | None = None,
|
|
14
|
+
body: dict[str, object] | None = None,
|
|
15
|
+
text: str | None = None,
|
|
16
|
+
url: str = "https://ghe.example/api/v3/graphql",
|
|
17
|
+
) -> requests.Response:
|
|
18
|
+
response = requests.Response()
|
|
19
|
+
response.status_code = 200
|
|
20
|
+
response.headers.update(headers or {})
|
|
21
|
+
if text is not None:
|
|
22
|
+
response._content = text.encode("utf-8")
|
|
23
|
+
else:
|
|
24
|
+
response._content = json.dumps(body or {}).encode("utf-8")
|
|
25
|
+
response.request = requests.Request("POST", url).prepare()
|
|
26
|
+
return response
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def test_retry_policy_recognizes_graphql_endpoint_without_resource_header() -> None:
|
|
30
|
+
response = graphql_response(
|
|
31
|
+
headers={"Retry-After": "0"},
|
|
32
|
+
body={"errors": [{"message": "temporary GraphQL failure"}]},
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
should_retry = github_retry_policy(BearerTokenAuth(token="static-token"))(
|
|
36
|
+
response,
|
|
37
|
+
None,
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
assert should_retry is True
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def test_retry_policy_retries_malformed_graphql_json() -> None:
|
|
44
|
+
response = graphql_response(text='{"data":{"organization":')
|
|
45
|
+
|
|
46
|
+
should_retry = github_retry_policy(BearerTokenAuth(token="static-token"))(
|
|
47
|
+
response,
|
|
48
|
+
None,
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
assert should_retry is True
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def test_retry_policy_does_not_retry_malformed_non_graphql_json() -> None:
|
|
55
|
+
response = graphql_response(
|
|
56
|
+
text='{"data":{"organization":',
|
|
57
|
+
url="https://ghe.example/api/v3/repos/example/repo",
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
should_retry = github_retry_policy(BearerTokenAuth(token="static-token"))(
|
|
61
|
+
response,
|
|
62
|
+
None,
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
assert should_retry is False
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def test_retry_client_recovers_from_malformed_graphql_json(monkeypatch) -> None:
|
|
69
|
+
responses = [
|
|
70
|
+
graphql_response(text='{"data":{"organization":'),
|
|
71
|
+
graphql_response(body={"data": {"organization": {"repositories": {}}}}),
|
|
72
|
+
]
|
|
73
|
+
requests_seen: list[requests.PreparedRequest] = []
|
|
74
|
+
|
|
75
|
+
def fake_send(
|
|
76
|
+
_session: Session,
|
|
77
|
+
request: requests.PreparedRequest,
|
|
78
|
+
**_kwargs,
|
|
79
|
+
) -> requests.Response:
|
|
80
|
+
response = responses[len(requests_seen)]
|
|
81
|
+
response.request = request
|
|
82
|
+
requests_seen.append(request)
|
|
83
|
+
return response
|
|
84
|
+
|
|
85
|
+
monkeypatch.setattr(Session, "send", fake_send)
|
|
86
|
+
session = Client(
|
|
87
|
+
raise_for_status=False,
|
|
88
|
+
status_codes=(),
|
|
89
|
+
exceptions=(),
|
|
90
|
+
request_max_attempts=2,
|
|
91
|
+
request_backoff_factor=0,
|
|
92
|
+
retry_condition=github_retry_policy(BearerTokenAuth(token="static-token")),
|
|
93
|
+
).session
|
|
94
|
+
request = requests.Request(
|
|
95
|
+
"POST",
|
|
96
|
+
"https://ghe.example/api/v3/graphql",
|
|
97
|
+
).prepare()
|
|
98
|
+
|
|
99
|
+
response = session.send(request)
|
|
100
|
+
|
|
101
|
+
assert response.json() == {"data": {"organization": {"repositories": {}}}}
|
|
102
|
+
assert len(requests_seen) == 2
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
import duckdb
|
|
2
|
+
import logging
|
|
3
|
+
from unittest.mock import MagicMock
|
|
4
|
+
|
|
5
|
+
from openhound_github.lookup import GithubLookup
|
|
6
|
+
from openhound_github.models.repository import Repository
|
|
7
|
+
from openhound_github.resources.organization import (
|
|
8
|
+
OrgContext,
|
|
9
|
+
SourceContext,
|
|
10
|
+
repositories_graphql,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class _FakeClient:
|
|
15
|
+
def __init__(self) -> None:
|
|
16
|
+
self.request_cursors: list[str | None] = []
|
|
17
|
+
|
|
18
|
+
def paginate(self, *args, **kwargs):
|
|
19
|
+
self.request_cursors.append(kwargs["json"]["variables"]["after"])
|
|
20
|
+
return iter(
|
|
21
|
+
[
|
|
22
|
+
[
|
|
23
|
+
_repository_page_data("R_1", "repo", branch_ruleset_count=2)
|
|
24
|
+
]
|
|
25
|
+
]
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _repository_page_data(
|
|
30
|
+
repository_id: str,
|
|
31
|
+
repository_name: str,
|
|
32
|
+
*,
|
|
33
|
+
branch_ruleset_count: int | None = None,
|
|
34
|
+
repository_end_cursor: str | None = None,
|
|
35
|
+
repositories_has_next_page: bool = False,
|
|
36
|
+
) -> dict:
|
|
37
|
+
return {
|
|
38
|
+
"organization": {
|
|
39
|
+
"repositories": {
|
|
40
|
+
"pageInfo": {
|
|
41
|
+
"endCursor": repository_end_cursor,
|
|
42
|
+
"hasNextPage": repositories_has_next_page,
|
|
43
|
+
},
|
|
44
|
+
"nodes": [
|
|
45
|
+
{
|
|
46
|
+
"id": repository_id,
|
|
47
|
+
"name": repository_name,
|
|
48
|
+
"branchRulesets": {"totalCount": branch_ruleset_count},
|
|
49
|
+
"refs": {
|
|
50
|
+
"nodes": [],
|
|
51
|
+
"pageInfo": {
|
|
52
|
+
"endCursor": None,
|
|
53
|
+
"hasNextPage": False,
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
}
|
|
57
|
+
]
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class _FailingSecondPageClient:
|
|
64
|
+
def __init__(self) -> None:
|
|
65
|
+
self.request_cursors: list[str | None] = []
|
|
66
|
+
|
|
67
|
+
def paginate(self, *args, **kwargs):
|
|
68
|
+
variables = kwargs["json"]["variables"]
|
|
69
|
+
self.request_cursors.append(variables["after"])
|
|
70
|
+
yield [
|
|
71
|
+
_repository_page_data(
|
|
72
|
+
"R_1",
|
|
73
|
+
"repo",
|
|
74
|
+
branch_ruleset_count=2,
|
|
75
|
+
repository_end_cursor="cursor-page-2",
|
|
76
|
+
repositories_has_next_page=True,
|
|
77
|
+
)
|
|
78
|
+
]
|
|
79
|
+
variables["after"] = "cursor-page-2"
|
|
80
|
+
self.request_cursors.append(variables["after"])
|
|
81
|
+
raise ConnectionError("GraphQL page failed after retries")
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class _TwoPageClient:
|
|
85
|
+
def __init__(self) -> None:
|
|
86
|
+
self.request_cursors: list[str | None] = []
|
|
87
|
+
|
|
88
|
+
def paginate(self, *args, **kwargs):
|
|
89
|
+
variables = kwargs["json"]["variables"]
|
|
90
|
+
pages = [
|
|
91
|
+
_repository_page_data(
|
|
92
|
+
"R_1",
|
|
93
|
+
"repo-1",
|
|
94
|
+
branch_ruleset_count=2,
|
|
95
|
+
repository_end_cursor="cursor-page-2",
|
|
96
|
+
repositories_has_next_page=True,
|
|
97
|
+
),
|
|
98
|
+
_repository_page_data("R_2", "repo-2", branch_ruleset_count=0),
|
|
99
|
+
]
|
|
100
|
+
for page in pages:
|
|
101
|
+
self.request_cursors.append(variables["after"])
|
|
102
|
+
yield [page]
|
|
103
|
+
page_info = page["organization"]["repositories"]["pageInfo"]
|
|
104
|
+
if page_info["hasNextPage"]:
|
|
105
|
+
variables["after"] = page_info["endCursor"]
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def _make_repository() -> Repository:
|
|
109
|
+
return Repository(
|
|
110
|
+
id=1,
|
|
111
|
+
node_id="R_1",
|
|
112
|
+
name="repo",
|
|
113
|
+
full_name="org/repo",
|
|
114
|
+
private=False,
|
|
115
|
+
size=0,
|
|
116
|
+
owner={
|
|
117
|
+
"login": "octocat",
|
|
118
|
+
"id": 1,
|
|
119
|
+
"node_id": "U_1",
|
|
120
|
+
"avatar_url": "",
|
|
121
|
+
"gravatar_id": "",
|
|
122
|
+
"url": "",
|
|
123
|
+
"html_url": "",
|
|
124
|
+
"followers_url": "",
|
|
125
|
+
"following_url": "",
|
|
126
|
+
"gists_url": "",
|
|
127
|
+
"starred_url": "",
|
|
128
|
+
"subscriptions_url": "",
|
|
129
|
+
"organizations_url": "",
|
|
130
|
+
"repos_url": "",
|
|
131
|
+
"events_url": "",
|
|
132
|
+
"received_events_url": "",
|
|
133
|
+
"type": "User",
|
|
134
|
+
"site_admin": False,
|
|
135
|
+
},
|
|
136
|
+
org_login="org",
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def test_repositories_graphql_flattens_branch_ruleset_count() -> None:
|
|
141
|
+
client = _FakeClient()
|
|
142
|
+
ctx = SourceContext(
|
|
143
|
+
client=client,
|
|
144
|
+
organizations=[OrgContext(client=client, org_name="org")],
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
rows = list(repositories_graphql.__wrapped__(ctx))
|
|
148
|
+
|
|
149
|
+
assert rows == [
|
|
150
|
+
{
|
|
151
|
+
"id": "R_1",
|
|
152
|
+
"name": "repo",
|
|
153
|
+
"refs": {
|
|
154
|
+
"nodes": [],
|
|
155
|
+
"pageInfo": {"endCursor": None, "hasNextPage": False},
|
|
156
|
+
},
|
|
157
|
+
"branch_ruleset_count": 2,
|
|
158
|
+
"org_login": "org",
|
|
159
|
+
}
|
|
160
|
+
]
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def test_repositories_graphql_logs_cursor_and_emitted_count_on_page_failure(
|
|
164
|
+
caplog,
|
|
165
|
+
) -> None:
|
|
166
|
+
client = _FailingSecondPageClient()
|
|
167
|
+
ctx = SourceContext(
|
|
168
|
+
client=client,
|
|
169
|
+
organizations=[OrgContext(client=client, org_name="org")],
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
with caplog.at_level(logging.ERROR, logger="openhound_github.resources.organization"):
|
|
173
|
+
rows = list(repositories_graphql.__wrapped__(ctx))
|
|
174
|
+
|
|
175
|
+
assert len(rows) == 1
|
|
176
|
+
assert (
|
|
177
|
+
"Error in resource 'repositories_graphql' processing organization 'org' "
|
|
178
|
+
"at repository cursor 'cursor-page-2' after emitting 1 repositories "
|
|
179
|
+
"(ConnectionError): GraphQL page failed after retries"
|
|
180
|
+
) in caplog.text
|
|
181
|
+
assert client.request_cursors == [None, "cursor-page-2"]
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def test_repositories_graphql_emits_all_repository_pages() -> None:
|
|
185
|
+
client = _TwoPageClient()
|
|
186
|
+
ctx = SourceContext(
|
|
187
|
+
client=client,
|
|
188
|
+
organizations=[OrgContext(client=client, org_name="org")],
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
rows = list(repositories_graphql.__wrapped__(ctx))
|
|
192
|
+
|
|
193
|
+
assert [(row["id"], row["branch_ruleset_count"]) for row in rows] == [
|
|
194
|
+
("R_1", 2),
|
|
195
|
+
("R_2", 0),
|
|
196
|
+
]
|
|
197
|
+
assert client.request_cursors == [None, "cursor-page-2"]
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def test_repository_node_surfaces_branch_ruleset_presence() -> None:
|
|
201
|
+
repo = _make_repository()
|
|
202
|
+
lookup = MagicMock()
|
|
203
|
+
lookup.org_id_for_login.return_value = "O_1"
|
|
204
|
+
lookup.repository_branch_ruleset_count.return_value = 2
|
|
205
|
+
repo._lookup = lookup
|
|
206
|
+
|
|
207
|
+
node = repo.as_node
|
|
208
|
+
|
|
209
|
+
assert node.properties.branch_ruleset_count == 2
|
|
210
|
+
assert node.properties.has_branch_rulesets is True
|
|
211
|
+
assert node.properties.size == 0
|
|
212
|
+
lookup.repository_branch_ruleset_count.assert_called_once_with("R_1")
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
def test_repository_node_preserves_unknown_branch_ruleset_presence() -> None:
|
|
216
|
+
repo = _make_repository()
|
|
217
|
+
lookup = MagicMock()
|
|
218
|
+
lookup.org_id_for_login.return_value = "O_1"
|
|
219
|
+
lookup.repository_branch_ruleset_count.return_value = None
|
|
220
|
+
repo._lookup = lookup
|
|
221
|
+
|
|
222
|
+
node = repo.as_node
|
|
223
|
+
|
|
224
|
+
assert node.properties.branch_ruleset_count is None
|
|
225
|
+
assert node.properties.has_branch_rulesets is None
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
def test_repository_branch_ruleset_count_lookup_returns_int() -> None:
|
|
229
|
+
connection = duckdb.connect(":memory:")
|
|
230
|
+
connection.execute("CREATE SCHEMA github")
|
|
231
|
+
connection.execute(
|
|
232
|
+
"CREATE TABLE github.repositories_graphql (id VARCHAR, branch_ruleset_count BIGINT)"
|
|
233
|
+
)
|
|
234
|
+
connection.execute(
|
|
235
|
+
"INSERT INTO github.repositories_graphql VALUES ('R_1', 2), ('R_2', NULL)"
|
|
236
|
+
)
|
|
237
|
+
|
|
238
|
+
lookup = GithubLookup(connection)
|
|
239
|
+
|
|
240
|
+
assert lookup.repository_branch_ruleset_count("R_1") == 2
|
|
241
|
+
assert lookup.repository_branch_ruleset_count("R_2") is None
|