openhound-github 0.6.0__tar.gz → 0.6.1__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.0 → openhound_github-0.6.1}/PKG-INFO +1 -1
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/auth.py +95 -7
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/helpers.py +18 -1
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/source.py +18 -3
- {openhound_github-0.6.0 → openhound_github-0.6.1}/tests/test_app_auth.py +27 -1
- openhound_github-0.6.1/tests/test_github_app_retry.py +216 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/.github/CODE_OF_CONDUCT.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/.github/CONTRIBUTING.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/.github/GOVERNANCE.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/.github/GitHub-COC-Header.png +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/.github/GitHub-CONTRIB-Header.png +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/.github/GitHub-GOV-Header.png +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/.github/GitHub-Header.png +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/.github/GitHub-LIC-Header.png +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/.github/GitHub-SEC-Header.png +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/.github/SECURITY.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/.github/SO-Dark.svg +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/.github/SO-FOSS-Dark.svg +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/.github/SO-FOSS-Light.svg +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/.github/SO-Light.svg +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/.github/workflows/publish.yml +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/.github/workflows/release-on-merge.yml +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/.github/workflows/validate-branch.yml +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/.gitignore +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/.gitmodules +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/.pre-commit-config.yaml +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/LICENSE.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/README.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_AddAssignee.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_AddCollaborator.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_AddLabel.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_AddMember.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_AdminTo.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_ApprovesDeploymentTo.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_AssignedTo.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_BypassBranchProtection.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_BypassPullRequestAllowances.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_CallsWorkflow.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_CanAccess.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_CanAssumeIdentity.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_CanCreateBranch.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_CanCreateEnvironment.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_CanCreateRepositoryWithRunnerAccess.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_CanDeployToEnvironment.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_CanEditEnvironment.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_CanEditProtection.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_CanPwnRequest.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_CanReadSecretScanningAlert.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_CanUseRunner.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_CanWriteBranch.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_CloseDiscussion.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_CloseIssue.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_ClosePullRequest.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_Contains.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_ConvertIssuesToDiscussions.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_CreateDiscussionCategory.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_CreateRepository.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_CreateSoloMergeQueueEntry.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_CreateTag.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_CreateTeam.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_DeleteAlertsCodeScanning.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_DeleteDiscussion.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_DeleteDiscussionComment.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_DeleteIssue.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_DeleteTag.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_DependsOn.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_DeploysTo.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_EditCategoryOnDiscussion.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_EditDiscussionCategory.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_EditDiscussionComment.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_EditRepoAnnouncementBanners.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_EditRepoCustomPropertiesValues.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_EditRepoMetadata.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_EditRepoProtections.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_HasBaseRole.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_HasBranch.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_HasEnvironment.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_HasExternalIdentity.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_HasJob.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_HasMember.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_HasPersonalAccessToken.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_HasPersonalAccessTokenRequest.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_HasRole.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_HasRunner.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_HasSamlIdentityProvider.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_HasSecret.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_HasStep.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_HasVariable.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_HasWorkflow.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_InheritedFrom.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_InstalledAs.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_InviteMember.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_IsEligibleFor.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_JumpMergeQueue.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_ManageDeployKeys.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_ManageDiscussionBadges.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_ManageOrganizationWebhooks.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_ManageRepoSecurityProducts.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_ManageSecurityProducts.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_ManageSettingsMergeTypes.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_ManageSettingsPages.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_ManageSettingsProjects.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_ManageSettingsWiki.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_ManageTopics.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_ManageWebhooks.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_MapsToUser.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_MarkAsDuplicate.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_MatchesEnvironmentPolicy.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_MemberOf.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_OrgBypassCodeScanningDismissalRequests.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_OrgBypassSecretScanningClosureRequests.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_OrgReviewAndManageSecretScanningBypassRequests.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_OrgReviewAndManageSecretScanningClosureRequests.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_Owns.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_ProtectedBy.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_PushProtectedBranch.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_ReadCodeScanning.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_ReadOrganizationActionsUsageMetrics.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_ReadOrganizationCustomOrgRole.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_ReadOrganizationCustomRepoRole.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_ReadRepoContents.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_RemoveAssignee.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_RemoveLabel.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_ReopenDiscussion.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_ReopenIssue.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_ReopenPullRequest.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_RequestPrReview.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_ResolveDependabotAlerts.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_ResolveSecretScanningAlerts.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_RestrictionsCanPush.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_RunOrgMigration.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_SetInteractionLimits.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_SetIssueType.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_SetMilestone.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_SetSocialPreview.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_SyncedTo.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_ToggleDiscussionAnswer.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_ToggleDiscussionCommentMinimize.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_TransferRepository.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_UsesSecret.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_UsesVariable.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_ValidToken.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_ViewDependabotAlerts.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_ViewSecretScanningAlerts.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_WriteCodeScanning.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_WriteOrganizationActionsSecrets.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_WriteOrganizationActionsSettings.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_WriteOrganizationActionsVariables.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_WriteOrganizationCustomOrgRole.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_WriteOrganizationCustomRepoRole.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_WriteOrganizationNetworkConfigurations.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_WriteRepoContents.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_WriteRepoPullRequests.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/nodes/GH_App.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/nodes/GH_AppInstallation.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/nodes/GH_Branch.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/nodes/GH_BranchProtectionRule.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/nodes/GH_EnterpriseRunner.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/nodes/GH_EnterpriseRunnerGroup.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/nodes/GH_Environment.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/nodes/GH_EnvironmentBranchPolicy.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/nodes/GH_EnvironmentSecret.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/nodes/GH_EnvironmentVariable.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/nodes/GH_ExternalIdentity.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/nodes/GH_OrgRole.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/nodes/GH_OrgRunner.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/nodes/GH_OrgRunnerGroup.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/nodes/GH_OrgSecret.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/nodes/GH_OrgVariable.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/nodes/GH_Organization.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/nodes/GH_PersonalAccessToken.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/nodes/GH_PersonalAccessTokenRequest.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/nodes/GH_RepoRole.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/nodes/GH_RepoRunner.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/nodes/GH_RepoSecret.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/nodes/GH_RepoVariable.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/nodes/GH_Repository.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/nodes/GH_SamlIdentityProvider.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/nodes/GH_SecretScanningAlert.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/nodes/GH_Team.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/nodes/GH_TeamRole.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/nodes/GH_User.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/nodes/GH_Workflow.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/nodes/GH_WorkflowJob.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/nodes/GH_WorkflowStep.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/docs/og-docs.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/extension/privilege_zone_rules/t0-all-repo-admin-role.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/extension/privilege_zone_rules/t0-app-installations-all-repos.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/extension/privilege_zone_rules/t0-apps-all-repos.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/extension/privilege_zone_rules/t0-external-identities-owners.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/extension/privilege_zone_rules/t0-organizations.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/extension/privilege_zone_rules/t0-owner-users.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/extension/privilege_zone_rules/t0-owners-role.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/extension/privilege_zone_rules/t0-pats-all-repos.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/extension/privilege_zone_rules/t0-privilege-escalation-roles.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/extension/privilege_zone_rules/t0-privilege-escalation-users.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/extension/privilege_zone_rules/t0-saml-identity-providers.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/extension/saved_searches/README.md +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/extension/saved_searches/actions-sha-pinning-not-required.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/extension/saved_searches/active-leaked-secrets.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/extension/saved_searches/advanced-security-disabled-new-repos.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/extension/saved_searches/all-actions-allowed.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/extension/saved_searches/app-installations-all-repos.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/extension/saved_searches/branch-protection-admins-not-enforced.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/extension/saved_searches/branch-protection-deletions-allowed.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/extension/saved_searches/branch-protection-force-pushes.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/extension/saved_searches/branch-protection-no-code-owner-reviews.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/extension/saved_searches/branch-protection-no-pr-reviews.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/extension/saved_searches/branch-protection-no-status-checks.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/extension/saved_searches/branch-protection-self-approval.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/extension/saved_searches/branch-protection-stale-reviews.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/extension/saved_searches/bypass-pr-requirements.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/extension/saved_searches/dangerous-branch-perms.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/extension/saved_searches/default-repository-permissions.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/extension/saved_searches/demo-sso-to-cloud-round-trip.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/extension/saved_searches/dependabot-alerts-disabled-new-repos.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/extension/saved_searches/dependabot-updates-disabled-new-repos.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/extension/saved_searches/dependency-graph-disabled-new-repos.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/extension/saved_searches/environments-admin-bypass.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/extension/saved_searches/expired-pats.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/extension/saved_searches/external-identities-without-scim.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/extension/saved_searches/github-to-azure-identity.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/extension/saved_searches/global-repo-perms.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/extension/saved_searches/hybrid-identities.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/extension/saved_searches/members-can-change-repo-visibility.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/extension/saved_searches/members-can-create-pages.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/extension/saved_searches/members-can-create-public-repos.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/extension/saved_searches/members-can-delete-repos.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/extension/saved_searches/members-can-fork-private-repos.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/extension/saved_searches/members-can-invite-outside-collaborators.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/extension/saved_searches/org-owners.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/extension/saved_searches/orgs-without-2fa.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/extension/saved_searches/pats-all-repo-access.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/extension/saved_searches/pending-pat-requests.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/extension/saved_searches/private-repos-forking-allowed.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/extension/saved_searches/privileged-custom-org-roles.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/extension/saved_searches/privileged-hybrid-identities.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/extension/saved_searches/public-repos.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/extension/saved_searches/push-protection-disabled-new-repos.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/extension/saved_searches/push-to-protected-branches.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/extension/saved_searches/repos-secret-scanning-disabled.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/extension/saved_searches/repos-vulnerable-to-workflow-secret-exfil.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/extension/saved_searches/repository-workflows.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/extension/saved_searches/saml-configuration.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/extension/saved_searches/secret-scanning-alerts.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/extension/saved_searches/secret-scanning-disabled-new-repos.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/extension/saved_searches/secrets-reachable-by-user.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/extension/saved_searches/team-membership-admin.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/extension/saved_searches/team-structure.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/extension/saved_searches/unprotected-branches.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/extension/saved_searches/unprotected-default-branch-with-workflow.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/extension/saved_searches/unprotected-default-branches.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/extension/saved_searches/web-commit-signoff-not-required.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/extension/schema.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/justfile +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/pyproject.toml +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/main.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/__init__.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/extension.yaml +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/graph.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/graphql.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/kinds/edges.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/kinds/nodes.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/lookup.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/main.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/models/__init__.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/models/actions_permission.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/models/app_installation.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/models/branch.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/models/branch_pr_bypass_allowance.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/models/branch_protection_rule.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/models/branch_push_allowance.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/models/enterprise.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/models/enterprise_admin.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/models/enterprise_helpers.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/models/enterprise_managed_user.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/models/enterprise_member.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/models/enterprise_organization.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/models/enterprise_role.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/models/enterprise_role_team.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/models/enterprise_role_user.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/models/enterprise_team.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/models/enterprise_team_member.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/models/enterprise_team_organization.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/models/enterprise_team_role.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/models/enterprise_user.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/models/env_secret.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/models/env_variable.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/models/environment.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/models/environment_branch_policy.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/models/external_identity.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/models/org.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/models/org_role.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/models/org_role_member.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/models/org_role_team.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/models/org_secret.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/models/org_variable.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/models/personal_access_token.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/models/personal_access_token_access.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/models/personal_access_token_request.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/models/projected_enterprise_team.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/models/repo_role_assignment.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/models/repository.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/models/repository_role.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/models/repository_secret.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/models/repository_variable.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/models/runner.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/models/saml_assertion_consumer_service.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/models/saml_helpers.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/models/saml_issuer.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/models/saml_provider.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/models/saml_service_provider.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/models/scim_user.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/models/secret_scanning_alert.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/models/team.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/models/team_member.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/models/team_role.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/models/user.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/models/workflow.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/models/workflow_job.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/models/workflow_step.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/resources/__init__.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/resources/enterprise.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/resources/organization.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/runner_ids.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/src/openhound_github/transforms.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/tests/test_branch_collection_gate.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/tests/test_branch_protection_traversability.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/tests/test_data/api/actions-permissions.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/tests/test_data/api/actionsecrets.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/tests/test_data/api/app.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/tests/test_data/api/appinstalls.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/tests/test_data/api/branch-policies.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/tests/test_data/api/branch-prot-rules.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/tests/test_data/api/branches.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/tests/test_data/api/custom-roles.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/tests/test_data/api/environments.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/tests/test_data/api/org-pat-request.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/tests/test_data/api/org-pat.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/tests/test_data/api/org-role-teams.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/tests/test_data/api/org-role-users.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/tests/test_data/api/org-roles.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/tests/test_data/api/org.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/tests/test_data/api/pat-repositories.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/tests/test_data/api/repo-collaborators.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/tests/test_data/api/repo-teams.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/tests/test_data/api/repositories.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/tests/test_data/api/scimusers.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/tests/test_data/api/secrets.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/tests/test_data/api/secretscanningalert.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/tests/test_data/api/selected-org-secrets.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/tests/test_data/api/variables.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/tests/test_data/api/workflows.json +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/tests/test_enterprise_capabilities.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/tests/test_enterprise_organization.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/tests/test_enterprise_resources.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/tests/test_environment_model.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/tests/test_environment_resources.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/tests/test_environment_reviewer_lookup.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/tests/test_error_resilience.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/tests/test_external_identity_tenant_matching.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/tests/test_github_rest_client.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/tests/test_github_retry.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/tests/test_org_secret_models.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/tests/test_repository_rulesets.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/tests/test_runner_ids.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/tests/test_runner_models.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/tests/test_runner_resources.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/tests/test_saml_helpers.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/tests/test_saml_models.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/tests/test_scim_models.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/tests/test_variable_models.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/tests/test_workflow_model.py +0 -0
- {openhound_github-0.6.0 → openhound_github-0.6.1}/uv.lock +0 -0
|
@@ -2,6 +2,8 @@ import logging
|
|
|
2
2
|
from datetime import datetime, timedelta, timezone
|
|
3
3
|
from threading import Lock
|
|
4
4
|
from typing import Iterator
|
|
5
|
+
from urllib.parse import urlparse
|
|
6
|
+
from weakref import WeakKeyDictionary
|
|
5
7
|
|
|
6
8
|
import requests
|
|
7
9
|
from dlt.common.configuration import configspec
|
|
@@ -17,6 +19,19 @@ from pydantic import BaseModel
|
|
|
17
19
|
logger = logging.getLogger(__name__)
|
|
18
20
|
|
|
19
21
|
|
|
22
|
+
def _normalized_http_origin(url: str) -> tuple[str, str, int | None]:
|
|
23
|
+
parsed = urlparse(url)
|
|
24
|
+
scheme = parsed.scheme.lower()
|
|
25
|
+
if scheme != "https" or not parsed.hostname:
|
|
26
|
+
raise ValueError("GitHub API URI must be an absolute HTTPS URL")
|
|
27
|
+
|
|
28
|
+
port = parsed.port
|
|
29
|
+
if scheme == "https" and port == 443:
|
|
30
|
+
port = None
|
|
31
|
+
|
|
32
|
+
return scheme, parsed.hostname.lower(), port
|
|
33
|
+
|
|
34
|
+
|
|
20
35
|
class AccountConfig(BaseModel):
|
|
21
36
|
id: int
|
|
22
37
|
login: str | None = None
|
|
@@ -63,7 +78,8 @@ class GithubSession:
|
|
|
63
78
|
private_key_path: str,
|
|
64
79
|
api_uri: str = "https://api.github.com/",
|
|
65
80
|
):
|
|
66
|
-
|
|
81
|
+
_normalized_http_origin(api_uri)
|
|
82
|
+
self.api_uri = f"{api_uri.rstrip('/')}/"
|
|
67
83
|
self.jwt_issuer = jwt_issuer
|
|
68
84
|
self.private_key_path = private_key_path
|
|
69
85
|
self.client = RESTClient(
|
|
@@ -158,11 +174,28 @@ class GitHubAppInstallationAuth(AuthConfigBase):
|
|
|
158
174
|
self,
|
|
159
175
|
installation: GithubInstallation,
|
|
160
176
|
refresh_margin_seconds: int = 300,
|
|
177
|
+
api_uri: str | None = None,
|
|
161
178
|
):
|
|
162
179
|
self.installation = installation
|
|
163
180
|
self.refresh_margin_seconds = refresh_margin_seconds
|
|
181
|
+
installation_api_uri = getattr(
|
|
182
|
+
installation, "api_uri", "https://api.github.com/"
|
|
183
|
+
)
|
|
184
|
+
selected_api_uri = api_uri or installation_api_uri
|
|
185
|
+
installation_api_origin = _normalized_http_origin(installation_api_uri)
|
|
186
|
+
selected_api_origin = _normalized_http_origin(selected_api_uri)
|
|
187
|
+
if selected_api_origin != installation_api_origin:
|
|
188
|
+
raise ValueError(
|
|
189
|
+
"GitHub App auth API URI origin must match installation API URI origin"
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
self.api_uri = selected_api_uri
|
|
193
|
+
self._api_origin = selected_api_origin
|
|
164
194
|
self.access_token: str | None = None
|
|
165
195
|
self.expires_at: datetime | None = None
|
|
196
|
+
self._response_refreshed_requests: WeakKeyDictionary[
|
|
197
|
+
requests.PreparedRequest, str
|
|
198
|
+
] = WeakKeyDictionary()
|
|
166
199
|
self._token_lock = Lock()
|
|
167
200
|
|
|
168
201
|
def _should_refresh(self) -> bool:
|
|
@@ -172,6 +205,14 @@ class GitHubAppInstallationAuth(AuthConfigBase):
|
|
|
172
205
|
refresh_at = self.expires_at - timedelta(seconds=self.refresh_margin_seconds)
|
|
173
206
|
return datetime.now(timezone.utc) >= refresh_at
|
|
174
207
|
|
|
208
|
+
def _refresh_token(self) -> None:
|
|
209
|
+
logger.info(
|
|
210
|
+
f"Refreshing access token for {self.installation.installation_id}"
|
|
211
|
+
)
|
|
212
|
+
get_token = self.installation.token
|
|
213
|
+
self.access_token = get_token.token
|
|
214
|
+
self.expires_at = get_token.expires_at
|
|
215
|
+
|
|
175
216
|
def token(self, force_refresh: bool = False) -> str | None:
|
|
176
217
|
if (
|
|
177
218
|
not force_refresh
|
|
@@ -182,15 +223,62 @@ class GitHubAppInstallationAuth(AuthConfigBase):
|
|
|
182
223
|
|
|
183
224
|
with self._token_lock:
|
|
184
225
|
if (force_refresh or self._should_refresh()) or self.access_token is None:
|
|
185
|
-
|
|
186
|
-
f"Refreshing access token for {self.installation.installation_id}"
|
|
187
|
-
)
|
|
188
|
-
get_token = self.installation.token
|
|
189
|
-
self.access_token = get_token.token
|
|
190
|
-
self.expires_at = get_token.expires_at
|
|
226
|
+
self._refresh_token()
|
|
191
227
|
|
|
192
228
|
return self.access_token
|
|
193
229
|
|
|
230
|
+
def refresh_request(self, request: requests.PreparedRequest) -> bool:
|
|
231
|
+
"""Repair a rejected same-origin request without stampeding token issuance."""
|
|
232
|
+
try:
|
|
233
|
+
request_origin = _normalized_http_origin(request.url or "")
|
|
234
|
+
except ValueError:
|
|
235
|
+
return False
|
|
236
|
+
|
|
237
|
+
if request_origin != self._api_origin:
|
|
238
|
+
return False
|
|
239
|
+
|
|
240
|
+
request_authorization = request.headers.get("Authorization")
|
|
241
|
+
if (
|
|
242
|
+
not request_authorization
|
|
243
|
+
or not request_authorization.startswith("Bearer ")
|
|
244
|
+
or not request_authorization.removeprefix("Bearer ").strip()
|
|
245
|
+
):
|
|
246
|
+
return False
|
|
247
|
+
|
|
248
|
+
with self._token_lock:
|
|
249
|
+
current_authorization = (
|
|
250
|
+
f"Bearer {self.access_token}" if self.access_token is not None else None
|
|
251
|
+
)
|
|
252
|
+
should_refresh = self._should_refresh()
|
|
253
|
+
repaired_authorization = self._response_refreshed_requests.get(request)
|
|
254
|
+
if (
|
|
255
|
+
not should_refresh
|
|
256
|
+
and request_authorization == current_authorization
|
|
257
|
+
and request_authorization == repaired_authorization
|
|
258
|
+
):
|
|
259
|
+
return False
|
|
260
|
+
|
|
261
|
+
if (
|
|
262
|
+
self.access_token is None
|
|
263
|
+
or should_refresh
|
|
264
|
+
or request_authorization == current_authorization
|
|
265
|
+
):
|
|
266
|
+
try:
|
|
267
|
+
self._refresh_token()
|
|
268
|
+
except Exception:
|
|
269
|
+
logger.warning(
|
|
270
|
+
"Failed to refresh GitHub App installation token for "
|
|
271
|
+
"installation %s during request retry",
|
|
272
|
+
self.installation.installation_id,
|
|
273
|
+
)
|
|
274
|
+
return False
|
|
275
|
+
|
|
276
|
+
replacement_authorization = f"Bearer {self.access_token}"
|
|
277
|
+
request.headers["Authorization"] = replacement_authorization
|
|
278
|
+
self._response_refreshed_requests[request] = replacement_authorization
|
|
279
|
+
|
|
280
|
+
return True
|
|
281
|
+
|
|
194
282
|
def __call__(self, request: requests.PreparedRequest) -> requests.PreparedRequest:
|
|
195
283
|
request.headers["Authorization"] = f"Bearer {self.token()}"
|
|
196
284
|
return request
|
|
@@ -10,6 +10,8 @@ from dlt.sources.helpers.rest_client.paginators import (
|
|
|
10
10
|
)
|
|
11
11
|
from requests import Request
|
|
12
12
|
|
|
13
|
+
from openhound_github.auth import GitHubAppInstallationAuth
|
|
14
|
+
|
|
13
15
|
logger = logging.getLogger(__name__)
|
|
14
16
|
|
|
15
17
|
|
|
@@ -160,6 +162,22 @@ def github_retry_policy(auth: AuthConfigBase):
|
|
|
160
162
|
|
|
161
163
|
headers = response.headers
|
|
162
164
|
now = int(time.time())
|
|
165
|
+
message = _response_message(response).lower()
|
|
166
|
+
|
|
167
|
+
# DLT retries the same prepared request after long Retry-After sleeps.
|
|
168
|
+
if (
|
|
169
|
+
response.status_code == 401
|
|
170
|
+
and "bad credentials" in message
|
|
171
|
+
and isinstance(auth, GitHubAppInstallationAuth)
|
|
172
|
+
and response.request is not None
|
|
173
|
+
):
|
|
174
|
+
if not auth.refresh_request(response.request):
|
|
175
|
+
return False
|
|
176
|
+
logger.warning(
|
|
177
|
+
"GitHub App installation token rejected, retrying request with refreshed token"
|
|
178
|
+
)
|
|
179
|
+
return True
|
|
180
|
+
|
|
163
181
|
if (
|
|
164
182
|
response.status_code == 200
|
|
165
183
|
and headers.get("x-ratelimit-resource") == "graphql"
|
|
@@ -178,7 +196,6 @@ def github_retry_policy(auth: AuthConfigBase):
|
|
|
178
196
|
return True
|
|
179
197
|
return False
|
|
180
198
|
|
|
181
|
-
message = _response_message(response).lower()
|
|
182
199
|
if response.status_code not in (403, 429):
|
|
183
200
|
return False
|
|
184
201
|
|
|
@@ -172,6 +172,7 @@ def source(
|
|
|
172
172
|
github_app_session = GithubApp(
|
|
173
173
|
jwt_issuer=jwt_issuer,
|
|
174
174
|
private_key_path=credentials.key_path,
|
|
175
|
+
api_uri=host,
|
|
175
176
|
)
|
|
176
177
|
for installation in github_app_session.installations:
|
|
177
178
|
if installation.target_type == "Organization":
|
|
@@ -179,12 +180,16 @@ def source(
|
|
|
179
180
|
installation_id=installation.id,
|
|
180
181
|
jwt_issuer=jwt_issuer,
|
|
181
182
|
private_key_path=credentials.key_path,
|
|
183
|
+
api_uri=host,
|
|
182
184
|
)
|
|
183
185
|
ctx.organizations.append(
|
|
184
186
|
OrgContext(
|
|
185
187
|
org_name=installation.account.login,
|
|
186
188
|
client=client(
|
|
187
|
-
GitHubAppInstallationAuth(
|
|
189
|
+
GitHubAppInstallationAuth(
|
|
190
|
+
installation=org_installation,
|
|
191
|
+
api_uri=host,
|
|
192
|
+
)
|
|
188
193
|
),
|
|
189
194
|
enterprise_name=credentials.enterprise_name,
|
|
190
195
|
github_deployment_id=github_deployment_id,
|
|
@@ -196,9 +201,13 @@ def source(
|
|
|
196
201
|
installation_id=installation.id,
|
|
197
202
|
jwt_issuer=jwt_issuer,
|
|
198
203
|
private_key_path=credentials.key_path,
|
|
204
|
+
api_uri=host,
|
|
199
205
|
)
|
|
200
206
|
ctx.client = client(
|
|
201
|
-
GitHubAppInstallationAuth(
|
|
207
|
+
GitHubAppInstallationAuth(
|
|
208
|
+
installation=es_installation,
|
|
209
|
+
api_uri=host,
|
|
210
|
+
)
|
|
202
211
|
)
|
|
203
212
|
|
|
204
213
|
return (*enterprise_resources(ctx), *organization_resources(ctx))
|
|
@@ -213,11 +222,17 @@ def source(
|
|
|
213
222
|
installation_id=credentials.install_id,
|
|
214
223
|
jwt_issuer=credentials.client_id,
|
|
215
224
|
private_key_path=credentials.key_path,
|
|
225
|
+
api_uri=host,
|
|
216
226
|
)
|
|
217
227
|
ctx.organizations.append(
|
|
218
228
|
OrgContext(
|
|
219
229
|
org_name=credentials.org_name,
|
|
220
|
-
client=client(
|
|
230
|
+
client=client(
|
|
231
|
+
GitHubAppInstallationAuth(
|
|
232
|
+
installation=org_installation,
|
|
233
|
+
api_uri=host,
|
|
234
|
+
)
|
|
235
|
+
),
|
|
221
236
|
github_deployment_id=github_deployment_id,
|
|
222
237
|
github_web_origin=github_web_origin,
|
|
223
238
|
)
|
|
@@ -9,6 +9,7 @@ from dlt.common.configuration.resolve import resolve_configuration
|
|
|
9
9
|
from openhound_github import auth
|
|
10
10
|
from openhound_github.auth import (
|
|
11
11
|
AccountConfig,
|
|
12
|
+
GitHubAppInstallationAuth,
|
|
12
13
|
GithubSession,
|
|
13
14
|
InstallationResponse,
|
|
14
15
|
resolve_github_app_jwt_issuer,
|
|
@@ -97,6 +98,28 @@ def test_legacy_installation_response_does_not_require_client_id() -> None:
|
|
|
97
98
|
assert installation.app_id == 123456
|
|
98
99
|
|
|
99
100
|
|
|
101
|
+
def test_github_app_installation_auth_rejects_mismatched_api_origins() -> None:
|
|
102
|
+
installation = SimpleNamespace(
|
|
103
|
+
installation_id="12345",
|
|
104
|
+
api_uri="https://ghe.example/api/v3/",
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
with pytest.raises(ValueError, match="must match installation API URI origin"):
|
|
108
|
+
GitHubAppInstallationAuth(
|
|
109
|
+
installation=installation,
|
|
110
|
+
api_uri="https://api.github.com/",
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def test_github_session_rejects_plaintext_api_uri() -> None:
|
|
115
|
+
with pytest.raises(ValueError, match="absolute HTTPS URL"):
|
|
116
|
+
GithubSession(
|
|
117
|
+
jwt_issuer="123456",
|
|
118
|
+
private_key_path="/tmp/github-app.pem",
|
|
119
|
+
api_uri="http://ghe.example/api/v3/",
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
|
|
100
123
|
def test_enterprise_source_reuses_selected_issuer_for_installation_tokens(
|
|
101
124
|
monkeypatch: pytest.MonkeyPatch,
|
|
102
125
|
) -> None:
|
|
@@ -104,7 +127,9 @@ def test_enterprise_source_reuses_selected_issuer_for_installation_tokens(
|
|
|
104
127
|
captured_issuers: list[str] = []
|
|
105
128
|
|
|
106
129
|
class FakeGithubApp:
|
|
107
|
-
def __init__(
|
|
130
|
+
def __init__(
|
|
131
|
+
self, jwt_issuer: str, private_key_path: str, api_uri: str
|
|
132
|
+
) -> None:
|
|
108
133
|
captured_issuers.append(jwt_issuer)
|
|
109
134
|
self.installations = (
|
|
110
135
|
SimpleNamespace(
|
|
@@ -125,6 +150,7 @@ def test_enterprise_source_reuses_selected_issuer_for_installation_tokens(
|
|
|
125
150
|
installation_id: int,
|
|
126
151
|
jwt_issuer: str,
|
|
127
152
|
private_key_path: str,
|
|
153
|
+
api_uri: str,
|
|
128
154
|
) -> None:
|
|
129
155
|
captured_issuers.append(jwt_issuer)
|
|
130
156
|
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from concurrent.futures import ThreadPoolExecutor
|
|
3
|
+
from datetime import datetime, timedelta, timezone
|
|
4
|
+
from threading import Event, Lock
|
|
5
|
+
|
|
6
|
+
import requests
|
|
7
|
+
from dlt.sources.helpers.rest_client.auth import BearerTokenAuth
|
|
8
|
+
|
|
9
|
+
from openhound_github.auth import GitHubAppInstallationAuth, TokenResponse
|
|
10
|
+
from openhound_github.helpers import github_retry_policy
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class FakeInstallation:
|
|
14
|
+
installation_id = "12345"
|
|
15
|
+
api_uri = "https://api.github.com/"
|
|
16
|
+
|
|
17
|
+
def __init__(self, *tokens: str) -> None:
|
|
18
|
+
self._tokens = iter(tokens)
|
|
19
|
+
self.token_calls = 0
|
|
20
|
+
|
|
21
|
+
@property
|
|
22
|
+
def token(self) -> TokenResponse:
|
|
23
|
+
self.token_calls += 1
|
|
24
|
+
return TokenResponse(
|
|
25
|
+
token=next(self._tokens),
|
|
26
|
+
expires_at=datetime.now(timezone.utc) + timedelta(hours=1),
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class BlockingFakeInstallation(FakeInstallation):
|
|
31
|
+
def __init__(self, *tokens: str) -> None:
|
|
32
|
+
super().__init__(*tokens)
|
|
33
|
+
self.token_started = Event()
|
|
34
|
+
self.release_token = Event()
|
|
35
|
+
|
|
36
|
+
@property
|
|
37
|
+
def token(self) -> TokenResponse:
|
|
38
|
+
self.token_started.set()
|
|
39
|
+
if not self.release_token.wait(timeout=1):
|
|
40
|
+
raise TimeoutError("timed out waiting to release fake token refresh")
|
|
41
|
+
return super().token
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class FailingFakeInstallation(FakeInstallation):
|
|
45
|
+
@property
|
|
46
|
+
def token(self) -> TokenResponse:
|
|
47
|
+
self.token_calls += 1
|
|
48
|
+
raise RuntimeError("sensitive-token-data")
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class TrackingLock:
|
|
52
|
+
def __init__(self) -> None:
|
|
53
|
+
self._lock = Lock()
|
|
54
|
+
self.waiting = Event()
|
|
55
|
+
|
|
56
|
+
def __enter__(self):
|
|
57
|
+
if not self._lock.acquire(blocking=False):
|
|
58
|
+
self.waiting.set()
|
|
59
|
+
self._lock.acquire()
|
|
60
|
+
return self
|
|
61
|
+
|
|
62
|
+
def __exit__(self, _exc_type, _exc_value, _traceback) -> None:
|
|
63
|
+
self._lock.release()
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def prepared_request(
|
|
67
|
+
token: str | None,
|
|
68
|
+
url: str = "https://api.github.com/repos/example/repo",
|
|
69
|
+
) -> requests.PreparedRequest:
|
|
70
|
+
headers = {"Authorization": f"Bearer {token}"} if token is not None else {}
|
|
71
|
+
return requests.Request(
|
|
72
|
+
"GET",
|
|
73
|
+
url,
|
|
74
|
+
headers=headers,
|
|
75
|
+
).prepare()
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def bad_credentials_response(
|
|
79
|
+
request: requests.PreparedRequest,
|
|
80
|
+
) -> requests.Response:
|
|
81
|
+
response = requests.Response()
|
|
82
|
+
response.status_code = 401
|
|
83
|
+
response._content = b'{"message":"Bad credentials"}'
|
|
84
|
+
response.request = request
|
|
85
|
+
return response
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def test_refresh_request_refreshes_rejected_current_token() -> None:
|
|
89
|
+
installation = FakeInstallation("new-token")
|
|
90
|
+
auth = GitHubAppInstallationAuth(installation=installation)
|
|
91
|
+
auth.access_token = "old-token"
|
|
92
|
+
auth.expires_at = datetime.now(timezone.utc) + timedelta(hours=1)
|
|
93
|
+
request = prepared_request("old-token")
|
|
94
|
+
|
|
95
|
+
auth.refresh_request(request)
|
|
96
|
+
|
|
97
|
+
assert request.headers["Authorization"] == "Bearer new-token"
|
|
98
|
+
assert auth.access_token == "new-token"
|
|
99
|
+
assert installation.token_calls == 1
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def test_refresh_request_reuses_token_refreshed_by_another_request() -> None:
|
|
103
|
+
installation = BlockingFakeInstallation("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
|
+
auth._token_lock = TrackingLock()
|
|
108
|
+
requests_to_refresh = [prepared_request("old-token"), prepared_request("old-token")]
|
|
109
|
+
|
|
110
|
+
with ThreadPoolExecutor(max_workers=2) as executor:
|
|
111
|
+
first_refresh = executor.submit(auth.refresh_request, requests_to_refresh[0])
|
|
112
|
+
assert installation.token_started.wait(timeout=1)
|
|
113
|
+
|
|
114
|
+
second_refresh = executor.submit(auth.refresh_request, requests_to_refresh[1])
|
|
115
|
+
assert auth._token_lock.waiting.wait(timeout=1)
|
|
116
|
+
|
|
117
|
+
installation.release_token.set()
|
|
118
|
+
first_refresh.result(timeout=1)
|
|
119
|
+
second_refresh.result(timeout=1)
|
|
120
|
+
|
|
121
|
+
assert all(
|
|
122
|
+
request.headers["Authorization"] == "Bearer new-token"
|
|
123
|
+
for request in requests_to_refresh
|
|
124
|
+
)
|
|
125
|
+
assert installation.token_calls == 1
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def test_refresh_request_does_not_restore_authorization_on_cross_origin_request() -> None:
|
|
129
|
+
installation = FakeInstallation("new-token")
|
|
130
|
+
auth = GitHubAppInstallationAuth(installation=installation)
|
|
131
|
+
auth.access_token = "old-token"
|
|
132
|
+
auth.expires_at = datetime.now(timezone.utc) + timedelta(hours=1)
|
|
133
|
+
request = prepared_request(None, url="https://attacker.example/redirected")
|
|
134
|
+
|
|
135
|
+
repaired = auth.refresh_request(request)
|
|
136
|
+
|
|
137
|
+
assert repaired is False
|
|
138
|
+
assert "Authorization" not in request.headers
|
|
139
|
+
assert installation.token_calls == 0
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def test_retry_policy_repairs_bad_credentials_for_github_app_auth() -> None:
|
|
143
|
+
installation = FakeInstallation("new-token")
|
|
144
|
+
auth = GitHubAppInstallationAuth(installation=installation)
|
|
145
|
+
auth.access_token = "old-token"
|
|
146
|
+
auth.expires_at = datetime.now(timezone.utc) + timedelta(hours=1)
|
|
147
|
+
request = prepared_request("old-token")
|
|
148
|
+
|
|
149
|
+
should_retry = github_retry_policy(auth)(bad_credentials_response(request), None)
|
|
150
|
+
|
|
151
|
+
assert should_retry is True
|
|
152
|
+
assert request.headers["Authorization"] == "Bearer new-token"
|
|
153
|
+
assert installation.token_calls == 1
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def test_retry_policy_does_not_retry_replacement_token_bad_credentials() -> None:
|
|
157
|
+
installation = FakeInstallation("new-token", "unused-token")
|
|
158
|
+
auth = GitHubAppInstallationAuth(installation=installation)
|
|
159
|
+
auth.access_token = "old-token"
|
|
160
|
+
auth.expires_at = datetime.now(timezone.utc) + timedelta(hours=1)
|
|
161
|
+
request = prepared_request("old-token")
|
|
162
|
+
retry_policy = github_retry_policy(auth)
|
|
163
|
+
|
|
164
|
+
assert retry_policy(bad_credentials_response(request), None) is True
|
|
165
|
+
assert request.headers["Authorization"] == "Bearer new-token"
|
|
166
|
+
|
|
167
|
+
assert retry_policy(bad_credentials_response(request), None) is False
|
|
168
|
+
assert request.headers["Authorization"] == "Bearer new-token"
|
|
169
|
+
assert installation.token_calls == 1
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def test_retry_policy_allows_fresh_request_to_refresh_replacement_token() -> None:
|
|
173
|
+
installation = FakeInstallation("new-token", "newer-token")
|
|
174
|
+
auth = GitHubAppInstallationAuth(installation=installation)
|
|
175
|
+
auth.access_token = "old-token"
|
|
176
|
+
auth.expires_at = datetime.now(timezone.utc) + timedelta(hours=1)
|
|
177
|
+
retry_policy = github_retry_policy(auth)
|
|
178
|
+
recovery_request = prepared_request("old-token")
|
|
179
|
+
|
|
180
|
+
assert retry_policy(bad_credentials_response(recovery_request), None) is True
|
|
181
|
+
assert recovery_request.headers["Authorization"] == "Bearer new-token"
|
|
182
|
+
|
|
183
|
+
independent_request = prepared_request("new-token")
|
|
184
|
+
|
|
185
|
+
assert retry_policy(bad_credentials_response(independent_request), None) is True
|
|
186
|
+
assert independent_request.headers["Authorization"] == "Bearer newer-token"
|
|
187
|
+
assert installation.token_calls == 2
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def test_retry_policy_does_not_retry_when_token_refresh_fails(caplog) -> None:
|
|
191
|
+
installation = FailingFakeInstallation()
|
|
192
|
+
auth = GitHubAppInstallationAuth(installation=installation)
|
|
193
|
+
auth.access_token = "old-token"
|
|
194
|
+
auth.expires_at = datetime.now(timezone.utc) + timedelta(hours=1)
|
|
195
|
+
request = prepared_request("old-token")
|
|
196
|
+
|
|
197
|
+
with caplog.at_level(logging.WARNING, logger="openhound_github.auth"):
|
|
198
|
+
should_retry = github_retry_policy(auth)(bad_credentials_response(request), None)
|
|
199
|
+
|
|
200
|
+
assert should_retry is False
|
|
201
|
+
assert request.headers["Authorization"] == "Bearer old-token"
|
|
202
|
+
assert installation.token_calls == 1
|
|
203
|
+
assert "Failed to refresh GitHub App installation token" in caplog.text
|
|
204
|
+
assert "sensitive-token-data" not in caplog.text
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
def test_retry_policy_does_not_repair_bad_credentials_for_bearer_token_auth() -> None:
|
|
208
|
+
request = prepared_request("static-token")
|
|
209
|
+
|
|
210
|
+
should_retry = github_retry_policy(BearerTokenAuth(token="static-token"))(
|
|
211
|
+
bad_credentials_response(request),
|
|
212
|
+
None,
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
assert should_retry is False
|
|
216
|
+
assert request.headers["Authorization"] == "Bearer static-token"
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_ApprovesDeploymentTo.md
RENAMED
|
File without changes
|
|
File without changes
|
{openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_BypassBranchProtection.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_CanAssumeIdentity.md
RENAMED
|
File without changes
|
|
File without changes
|
{openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_CanCreateEnvironment.md
RENAMED
|
File without changes
|
|
File without changes
|
{openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_CanDeployToEnvironment.md
RENAMED
|
File without changes
|
{openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_CanEditEnvironment.md
RENAMED
|
File without changes
|
{openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_CanEditProtection.md
RENAMED
|
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.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_CreateDiscussionCategory.md
RENAMED
|
File without changes
|
|
File without changes
|
{openhound_github-0.6.0 → openhound_github-0.6.1}/descriptions/edges/GH_CreateSoloMergeQueueEntry.md
RENAMED
|
File without changes
|