openhound-github 0.8.0__tar.gz → 0.9.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {openhound_github-0.8.0 → openhound_github-0.9.0}/PKG-INFO +1 -1
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_CanPwnRequest.md +1 -1
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_Repository.md +4 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_Workflow.md +3 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_WorkflowJob.md +5 -1
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/README.md +17 -13
- openhound_github-0.9.0/extension/saved_searches/workflow-jobs-with-broad-token-write-permissions.json +5 -0
- openhound_github-0.9.0/extension/saved_searches/workflow-jobs-with-id-token-write-on-self-hosted-runners.json +5 -0
- openhound_github-0.9.0/extension/saved_searches/workflow-jobs-with-id-token-write.json +5 -0
- openhound_github-0.9.0/extension/saved_searches/workflow-jobs-with-observed-oidc-auth-steps.json +5 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/lookup.py +28 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/repository.py +10 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/workflow.py +149 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/workflow_job.py +35 -16
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/resources/organization.py +34 -2
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/source.py +3 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/transforms.py +18 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_repository_rulesets.py +24 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_workflow_model.py +187 -1
- openhound_github-0.9.0/tests/test_workflow_resources.py +98 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/.github/CODE_OF_CONDUCT.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/.github/CONTRIBUTING.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/.github/GOVERNANCE.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/.github/GitHub-COC-Header.png +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/.github/GitHub-CONTRIB-Header.png +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/.github/GitHub-GOV-Header.png +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/.github/GitHub-Header.png +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/.github/GitHub-LIC-Header.png +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/.github/GitHub-SEC-Header.png +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/.github/SECURITY.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/.github/SO-Dark.svg +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/.github/SO-FOSS-Dark.svg +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/.github/SO-FOSS-Light.svg +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/.github/SO-Light.svg +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/.github/workflows/publish.yml +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/.github/workflows/release-on-merge.yml +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/.github/workflows/validate-branch.yml +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/.gitignore +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/.gitmodules +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/.pre-commit-config.yaml +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/LICENSE.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/README.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_AddAssignee.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_AddCollaborator.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_AddLabel.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_AddMember.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_AdminTo.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ApprovesDeploymentTo.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_AssignedTo.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_BypassBranchProtection.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_BypassPullRequestAllowances.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_CallsWorkflow.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_CanAccess.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_CanAssumeIdentity.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_CanCreateBranch.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_CanCreateEnvironment.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_CanCreateInternalRepositories.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_CanCreatePrivateRepositories.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_CanCreatePublicRepositories.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_CanCreateRepositories.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_CanCreateRepositoryWithRunnerAccess.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_CanDeployToEnvironment.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_CanEditEnvironment.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_CanEditProtection.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_CanReadSecret.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_CanReadSecretScanningAlert.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_CanUseRunner.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_CanWriteBranch.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_CloseDiscussion.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_CloseIssue.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ClosePullRequest.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_Contains.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ConvertIssuesToDiscussions.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_CreateDiscussionCategory.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_CreateEnterpriseOrganizations.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_CreateRepository.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_CreateSoloMergeQueueEntry.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_CreateTag.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_CreateTeam.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_DeleteAlertsCodeScanning.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_DeleteDiscussion.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_DeleteDiscussionComment.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_DeleteIssue.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_DeleteTag.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_DependsOn.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_DeploysTo.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_EditCategoryOnDiscussion.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_EditDiscussionCategory.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_EditDiscussionComment.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_EditEnterpriseCustomPropertiesForOrganizations.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_EditRepoAnnouncementBanners.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_EditRepoCustomPropertiesValues.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_EditRepoMetadata.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_EditRepoProtections.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_HasBaseRole.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_HasExternalIdentity.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_HasMember.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_HasPersonalAccessToken.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_HasPersonalAccessTokenRequest.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_HasRole.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_HasRunner.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_HasSamlIdentityProvider.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_HasSecret.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_HasVariable.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_InheritedFrom.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_InstalledAs.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_InviteMember.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_IsEligibleFor.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_JumpMergeQueue.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ManageDeployKeys.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ManageDiscussionBadges.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ManageEnterpriseAdmins.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ManageEnterpriseIdentityProvider.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ManageEnterpriseMembers.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ManageEnterpriseOrganizationAdmins.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ManageEnterpriseOrganizations.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ManageEnterpriseReferrals.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ManageEnterpriseTeams.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ManageOrganizationWebhooks.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ManageRepoSecurityProducts.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ManageSecurityProducts.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ManageSettingsMergeTypes.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ManageSettingsPages.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ManageSettingsProjects.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ManageSettingsWiki.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ManageTopics.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ManageWebhooks.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_MapsToUser.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_MarkAsDuplicate.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_MatchesEnvironmentPolicy.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_MemberOf.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_OrgBypassCodeScanningDismissalRequests.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_OrgBypassSecretScanningClosureRequests.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_OrgReviewAndManageSecretScanningBypassRequests.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_OrgReviewAndManageSecretScanningClosureRequests.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_Owns.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ProtectedBy.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_PushProtectedBranch.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ReadCodeScanning.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ReadEnterpriseAuditLog.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ReadEnterpriseDomainVerification.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ReadEnterpriseMembers.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ReadEnterpriseOrgProjects.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ReadEnterpriseOrganizationAdmin.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ReadOrganizationActionsUsageMetrics.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ReadOrganizationCustomOrgRole.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ReadOrganizationCustomRepoRole.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ReadRepoContents.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_RemoveAssignee.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_RemoveLabel.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ReopenDiscussion.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ReopenIssue.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ReopenPullRequest.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_RequestPrReview.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ResolveDependabotAlerts.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ResolveSecretScanningAlerts.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_RestrictionsCanPush.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_RunOrgMigration.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_RunsOn.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_SetEnterpriseInteractionLimits.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_SetInteractionLimits.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_SetIssueType.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_SetMilestone.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_SetSocialPreview.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_SyncedTo.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ToggleDiscussionAnswer.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ToggleDiscussionCommentMinimize.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_TransferRepository.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_UsesSecret.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_UsesVariable.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ValidToken.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ViewDependabotAlerts.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ViewEnterpriseActionsUsageMetrics.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ViewEnterpriseBilling.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ViewEnterpriseSecretScanningAlerts.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ViewSecretScanningAlerts.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_WriteCodeScanning.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_WriteEnterpriseActionsPolicies.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_WriteEnterpriseBilling.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_WriteEnterprisePersonalAccessTokenPolicies.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_WriteEnterpriseSso.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_WriteEnterpriseTeamMembers.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_WriteOrganizationActionsSecrets.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_WriteOrganizationActionsSettings.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_WriteOrganizationActionsVariables.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_WriteOrganizationCustomOrgRole.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_WriteOrganizationCustomRepoRole.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_WriteOrganizationNetworkConfigurations.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_WriteRepoContents.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_WriteRepoPullRequests.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_App.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_AppInstallation.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_Branch.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_BranchProtectionRule.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_Enterprise.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_EnterpriseManagedUser.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_EnterpriseRole.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_EnterpriseRunner.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_EnterpriseRunnerGroup.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_EnterpriseTeam.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_Environment.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_EnvironmentBranchPolicy.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_EnvironmentSecret.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_EnvironmentVariable.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_ExternalIdentity.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_OrgRole.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_OrgRunner.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_OrgRunnerGroup.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_OrgSecret.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_OrgVariable.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_Organization.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_PersonalAccessToken.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_PersonalAccessTokenRequest.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_RepoRole.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_RepoRunner.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_RepoSecret.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_RepoVariable.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_Runner.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_RunnerGroup.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_SamlIdentityProvider.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_Secret.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_SecretScanningAlert.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_Team.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_TeamRole.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_User.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_Variable.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_WorkflowStep.md +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/docs/og-docs.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/privilege_zone_rules/t0-all-repo-admin-role.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/privilege_zone_rules/t0-app-installations-all-repos.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/privilege_zone_rules/t0-apps-all-repos.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/privilege_zone_rules/t0-enterprise-owners-role.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/privilege_zone_rules/t0-external-identities-owners.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/privilege_zone_rules/t0-organizations.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/privilege_zone_rules/t0-owner-users.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/privilege_zone_rules/t0-owners-role.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/privilege_zone_rules/t0-pats-all-repos.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/privilege_zone_rules/t0-privilege-escalation-roles.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/privilege_zone_rules/t0-privilege-escalation-users.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/privilege_zone_rules/t0-saml-identity-providers.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/actions-sha-pinning-not-required.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/active-leaked-secrets.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/advanced-security-disabled-new-repos.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/all-actions-allowed.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/app-installations-all-repos.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/branch-protection-admins-not-enforced.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/branch-protection-deletions-allowed.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/branch-protection-force-pushes.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/branch-protection-no-code-owner-reviews.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/branch-protection-no-pr-reviews.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/branch-protection-no-status-checks.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/branch-protection-self-approval.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/branch-protection-stale-reviews.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/bypass-pr-requirements.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/dangerous-branch-perms.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/default-repository-permissions.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/demo-sso-to-cloud-round-trip.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/dependabot-alerts-disabled-new-repos.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/dependabot-updates-disabled-new-repos.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/dependency-graph-disabled-new-repos.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/environments-admin-bypass.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/expired-pats.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/external-identities-without-scim.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/github-to-azure-identity.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/global-repo-perms.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/hybrid-identities.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/members-can-change-repo-visibility.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/members-can-create-pages.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/members-can-create-public-repos.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/members-can-delete-repos.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/members-can-fork-private-repos.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/members-can-invite-outside-collaborators.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/org-owners.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/orgs-without-2fa.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/pats-all-repo-access.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/pending-pat-requests.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/private-repos-forking-allowed.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/privileged-custom-org-roles.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/privileged-hybrid-identities.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/public-repos.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/push-protection-disabled-new-repos.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/push-to-protected-branches.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/repos-secret-scanning-disabled.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/repos-vulnerable-to-workflow-secret-exfil.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/repository-workflows.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/saml-configuration.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/secret-scanning-alerts.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/secret-scanning-disabled-new-repos.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/secrets-reachable-by-user.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/team-membership-admin.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/team-structure.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/unprotected-branches.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/unprotected-default-branch-with-workflow.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/unprotected-default-branches.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/web-commit-signoff-not-required.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/schema.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/justfile +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/pyproject.toml +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/scripts/generate_gh_description_docs.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/main.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/__init__.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/auth.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/extension.yaml +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/github_rest_client.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/github_retry.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/graph.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/graphql.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/helpers.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/kinds/edges.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/kinds/nodes.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/main.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/__init__.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/actions_permission.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/app_installation.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/branch.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/branch_pr_bypass_allowance.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/branch_protection_rule.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/branch_push_allowance.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/enterprise.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/enterprise_admin.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/enterprise_helpers.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/enterprise_managed_user.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/enterprise_member.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/enterprise_organization.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/enterprise_role.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/enterprise_role_team.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/enterprise_role_user.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/enterprise_team.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/enterprise_team_member.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/enterprise_team_organization.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/enterprise_team_role.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/enterprise_user.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/env_secret.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/env_variable.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/environment.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/environment_branch_policy.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/external_identity.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/org.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/org_role.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/org_role_member.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/org_role_team.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/org_secret.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/org_variable.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/personal_access_token.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/personal_access_token_access.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/personal_access_token_request.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/projected_enterprise_team.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/repo_role_assignment.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/repository_role.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/repository_secret.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/repository_variable.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/runner.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/saml_assertion_consumer_service.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/saml_helpers.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/saml_issuer.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/saml_provider.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/saml_service_provider.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/scim_user.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/secret_scanning_alert.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/team.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/team_member.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/team_role.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/user.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/workflow_step.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/resources/__init__.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/resources/enterprise.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/runner_ids.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_app_auth.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_branch_collection_gate.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_branch_protection_traversability.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_data/api/actions-permissions.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_data/api/actionsecrets.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_data/api/app.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_data/api/appinstalls.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_data/api/branch-policies.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_data/api/branch-prot-rules.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_data/api/branches.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_data/api/custom-roles.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_data/api/environments.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_data/api/org-pat-request.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_data/api/org-pat.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_data/api/org-role-teams.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_data/api/org-role-users.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_data/api/org-roles.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_data/api/org.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_data/api/pat-repositories.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_data/api/repo-collaborators.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_data/api/repo-teams.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_data/api/repositories.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_data/api/scimusers.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_data/api/secrets.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_data/api/secretscanningalert.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_data/api/selected-org-secrets.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_data/api/variables.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_data/api/workflows.json +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_description_docs.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_enterprise_capabilities.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_enterprise_organization.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_enterprise_resources.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_environment_model.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_environment_resources.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_environment_reviewer_lookup.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_error_resilience.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_github_app_retry.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_github_rest_client.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_github_retry.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_helpers.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_lookup.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_org_scim_resources.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_org_secret_models.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_runner_ids.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_runner_models.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_runner_resources.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_saml_helpers.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_saml_models.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_scim_models.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_source_endpoints.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_source_org_canonicalization.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_team_external_groups.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_variable_models.py +0 -0
- {openhound_github-0.8.0 → openhound_github-0.9.0}/uv.lock +0 -0
|
@@ -41,7 +41,7 @@ An attacker who exploits a pwn request gains code execution in the workflow runn
|
|
|
41
41
|
|
|
42
42
|
### Caveats
|
|
43
43
|
|
|
44
|
-
- **OIDC traversal requires `id-token: write`**: The attack chain from GH_CanPwnRequest through GH_CanAssumeIdentity to a cloud role is only valid if the pwn-requestable
|
|
44
|
+
- **OIDC traversal requires `id-token: write`**: The attack chain from GH_CanPwnRequest through GH_CanAssumeIdentity to a cloud role is only valid if the pwn-requestable job's calculated `effective_github_token_permissions` includes `id-token:write`. The `id-token` permission defaults to `none` and is never implicitly granted — even when the workflow has no `permissions:` block at all. Inspect `workflow_permissions` on GH_Workflow, `job_permissions` on GH_WorkflowJob, and the job's `effective_github_token_permissions` to understand how the effective value was derived.
|
|
45
45
|
- **GITHUB_TOKEN permissions**: The `permissions:` block controls what the `GITHUB_TOKEN` can do (e.g., push commits, create releases), but has no effect on secret access, OIDC token requests (governed separately by `id-token`), or arbitrary code execution. A workflow with `contents: read` is still fully exploitable via pwn request for secret exfiltration and lateral movement — only write-back to the repository is limited.
|
|
46
46
|
|
|
47
47
|
## Edge Schema
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
Represents a GitHub repository within the organization. Repository nodes capture metadata about the repo including visibility, Actions enablement status, and security configuration. Repository role nodes (GH_RepoRole) are created alongside each repository to represent the permission levels available.
|
|
6
6
|
|
|
7
|
+
For repositories with active workflows, the collector records the applicable default workflow permissions and whether workflows may approve pull request reviews. These properties preserve the repository-level policy input later used to derive effective GITHUB_TOKEN permissions for GH_WorkflowJob nodes.
|
|
8
|
+
|
|
7
9
|
## Properties
|
|
8
10
|
|
|
9
11
|
| Property | Type | Description |
|
|
@@ -40,6 +42,8 @@ Represents a GitHub repository within the organization. Repository nodes capture
|
|
|
40
42
|
| `secret_scanning` | `string` | Status of secret scanning (e.g., `enabled`, `disabled`). |
|
|
41
43
|
| `branch_ruleset_count` | `integer` | Number of branch-targeted rulesets that apply to this repository. |
|
|
42
44
|
| `has_branch_rulesets` | `boolean` | Whether at least one branch-targeted ruleset applies to this repository. |
|
|
45
|
+
| `default_workflow_permissions` | `string` | The repository's applicable default GITHUB_TOKEN workflow permissions. |
|
|
46
|
+
| `can_approve_pull_request_reviews` | `boolean` | Whether workflows may approve pull request reviews. |
|
|
43
47
|
| `query_branches` | `string` | Query for branches. |
|
|
44
48
|
| `query_protected_branches` | `string` | Query for protected branches. |
|
|
45
49
|
| `query_branch_protection_rules` | `string` | Query for branch protection rules. |
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
Represents a GitHub Actions workflow defined in a repository. Workflow nodes capture the workflow definition metadata including its file path, state, containing repository, and the full YAML contents of the workflow file. Only repositories with GitHub Actions enabled are queried for workflows.
|
|
6
6
|
|
|
7
|
+
When present, `workflow_permissions` captures the top-level `permissions` declaration from the workflow YAML.
|
|
8
|
+
|
|
7
9
|
## Properties
|
|
8
10
|
|
|
9
11
|
| Property | Type | Description |
|
|
@@ -25,6 +27,7 @@ Represents a GitHub Actions workflow defined in a repository. Workflow nodes cap
|
|
|
25
27
|
| `triggers` | `list[string]` | The triggers value. |
|
|
26
28
|
| `trigger_dispatch_inputs` | `list[string]` | The trigger dispatch inputs value. |
|
|
27
29
|
| `is_pwn_requestable` | `boolean` | The is pwn requestable value. |
|
|
30
|
+
| `workflow_permissions` | `list[string]` | Permissions declared at the workflow level. |
|
|
28
31
|
| `query_repository` | `string` | Query for repository. |
|
|
29
32
|
| `query_jobs` | `string` | Query for workflow jobs. |
|
|
30
33
|
| `query_execution` | `string` | Query for workflow executions. |
|
|
@@ -6,6 +6,8 @@ Represents a single job within a GitHub Actions workflow. Jobs are the top-level
|
|
|
6
6
|
|
|
7
7
|
When the job has a statically resolvable self-hosted `runs-on` selector, GH_RunsOn edges identify each GH_Runner that currently satisfies the declared label and runner-group constraints under the repository's runner access policy. These edges represent schedulability, not historical execution.
|
|
8
8
|
|
|
9
|
+
When present, `job_permissions` captures the job-level `permissions` declaration from the workflow YAML. `effective_github_token_permissions` captures the calculated static `GITHUB_TOKEN` permissions after applying the repository default, workflow-level declaration, and job-level declaration.
|
|
10
|
+
|
|
9
11
|
## Properties
|
|
10
12
|
|
|
11
13
|
| Property | Type | Description |
|
|
@@ -23,7 +25,9 @@ When the job has a statically resolvable self-hosted `runs-on` selector, GH_Runs
|
|
|
23
25
|
| `is_self_hosted` | `boolean` | Whether the job targets self-hosted runners. |
|
|
24
26
|
| `container` | `string` | The optional container configuration. |
|
|
25
27
|
| `environment` | `string` | The deployment environment name. |
|
|
26
|
-
| `permissions` | `list[string]` |
|
|
28
|
+
| `permissions` | `list[string]` | Applicable declared workflow or job permissions after job-over-workflow precedence. |
|
|
29
|
+
| `job_permissions` | `list[string]` | Optional permissions declared at the job level; absent when the job has no declaration. |
|
|
30
|
+
| `effective_github_token_permissions` | `list[string]` | Calculated GITHUB_TOKEN permissions after repository defaults and declarations are applied. |
|
|
27
31
|
| `uses_reusable` | `string` | The reusable workflow reference used by this job. |
|
|
28
32
|
| `workflow_node_id` | `string` | The parent workflow node ID. |
|
|
29
33
|
| `repository_name` | `string` | The containing repository name. |
|
|
@@ -79,21 +79,25 @@ Pre-built Cypher queries for identifying security-relevant configurations across
|
|
|
79
79
|
| 39 | `dangerous-branch-perms.json` | Dangerous Branch Permissions | Identifies users with dangerous branch permissions in a GitHub organization, including bypass allowances on protection rules. |
|
|
80
80
|
| 40 | `org-roles-bypass-security-scanning.json` | Org Roles That Can Bypass Security Scanning | Finds organization roles with permissions to bypass or manage security scanning dismissals. These roles can suppress secret scanning and code scanning findings. |
|
|
81
81
|
| 41 | `github-to-azure-identity.json` | GitHub-to-Azure Identity Assumptions | Finds GitHub entities (repositories, branches, environments) that can assume Azure identities via OIDC federation. Verify that each trust relationship is intentional and scoped appropriately. |
|
|
82
|
+
| 42 | `workflow-jobs-with-id-token-write.json` | Workflow Jobs with OIDC Token Permission | Returns workflow jobs whose effective GITHUB_TOKEN permissions include `id-token:write`. |
|
|
83
|
+
| 43 | `workflow-jobs-with-id-token-write-on-self-hosted-runners.json` | OIDC-Capable Workflow Jobs on Self-Hosted Runners | Returns OIDC-capable jobs that can be scheduled on collected self-hosted runners. |
|
|
84
|
+
| 44 | `workflow-jobs-with-broad-token-write-permissions.json` | Workflow Jobs with Broad GITHUB_TOKEN Write Permissions | Returns jobs with effective write access to repository contents, Actions, or pull requests. |
|
|
85
|
+
| 45 | `workflow-jobs-with-observed-oidc-auth-steps.json` | Workflow Jobs with Observed OIDC Authentication Steps | Returns OIDC-capable jobs with descendant steps that show likely token consumption. |
|
|
82
86
|
|
|
83
87
|
### :white_circle: Low — Hygiene & Governance
|
|
84
88
|
|
|
85
89
|
| # | File | Name | Description |
|
|
86
90
|
|---|------|------|-------------|
|
|
87
|
-
|
|
|
88
|
-
|
|
|
89
|
-
|
|
|
90
|
-
|
|
|
91
|
-
|
|
|
92
|
-
|
|
|
93
|
-
|
|
|
94
|
-
|
|
|
95
|
-
|
|
|
96
|
-
|
|
|
97
|
-
|
|
|
98
|
-
|
|
|
99
|
-
|
|
|
91
|
+
| 46 | `environments-admin-bypass.json` | Environments Where Admins Can Bypass Protections | Finds deployment environments where administrators can bypass protection rules such as required reviewers and wait timers. Admins can deploy to these environments without any approval. |
|
|
92
|
+
| 47 | `app-installations-all-repos.json` | App Installations with Access to All Repositories | Finds GitHub App installations that have access to every repository in the organization. A compromised app credential would affect all repositories. |
|
|
93
|
+
| 48 | `users-without-external-identity.json` | GitHub Users Without External Identity Mapping | Finds GitHub users that are not linked to any external identity via SAML or SCIM. These users cannot be centrally offboarded through the identity provider and may retain access after employment ends. |
|
|
94
|
+
| 49 | `external-identities-without-scim.json` | External Identities Without SCIM Provisioning | Finds external identities that lack SCIM synchronization. Without SCIM, user deprovisioning in the identity provider will not automatically revoke GitHub access. |
|
|
95
|
+
| 50 | `org-owners.json` | Organization Owners | Returns all users who hold the organization owners role. |
|
|
96
|
+
| 51 | `privileged-custom-org-roles.json` | Privileged Custom Org Roles | Returns all custom organization roles that are privileged (i.e., have permissions that are not default). |
|
|
97
|
+
| 52 | `global-repo-perms.json` | Global Repo Permissions | Returns all users who hold a global repository permission role (i.e., roles that are not default). |
|
|
98
|
+
| 53 | `hybrid-identities.json` | External Identities | Returns all external identities (e.g., Azure or Okta users) that are associated with GitHub users. |
|
|
99
|
+
| 54 | `privileged-hybrid-identities.json` | Privileged Hybrid Identities | Returns all hybrid identities (e.g., Azure or Okta users) that are associated with GitHub users who hold the organization owners role. |
|
|
100
|
+
| 55 | `saml-configuration.json` | SAML Configuration Mapping | Finds SAML Identity Providers, their external identities, and mapped users. |
|
|
101
|
+
| 56 | `team-membership-admin.json` | Team Membership Admins | Returns all users who hold the maintainer role over a team, including team nesting. |
|
|
102
|
+
| 57 | `team-structure.json` | Team Structure | Returns the structure of teams within organizations, including team roles and their members. |
|
|
103
|
+
| 58 | `repository-workflows.json` | Repository Workflows | Returns all repository workflows. |
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "GitHub: Workflow Jobs with Broad GITHUB_TOKEN Write Permissions",
|
|
3
|
+
"query": "MATCH p=(repo:GH_Repository)-[:GH_Contains]->(:GH_Workflow)-[:GH_Contains]->(job:GH_WorkflowJob)\nWHERE 'contents:write' IN job.effective_github_token_permissions\nOR 'actions:write' IN job.effective_github_token_permissions\nOR 'pull-requests:write' IN job.effective_github_token_permissions\nRETURN p\nLIMIT 1000",
|
|
4
|
+
"description": "Returns workflow jobs whose calculated effective GITHUB_TOKEN permissions include write access to repository contents, Actions, or pull requests. These permissions can materially increase the impact of workflow compromise."
|
|
5
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "GitHub: OIDC-Capable Workflow Jobs on Self-Hosted Runners",
|
|
3
|
+
"query": "MATCH p=(repo:GH_Repository)-[:GH_Contains]->(:GH_Workflow)-[:GH_Contains]->(job:GH_WorkflowJob)-[:GH_RunsOn]->(:GH_Runner)\nWHERE 'id-token:write' IN job.effective_github_token_permissions\nRETURN p\nLIMIT 1000",
|
|
4
|
+
"description": "Returns OIDC-capable workflow jobs that can be scheduled on collected self-hosted runners. These jobs are especially important to review because runner compromise could expose short-lived cloud federation tokens."
|
|
5
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "GitHub: Workflow Jobs with OIDC Token Permission",
|
|
3
|
+
"query": "MATCH p=(repo:GH_Repository)-[:GH_Contains]->(:GH_Workflow)-[:GH_Contains]->(job:GH_WorkflowJob)\nWHERE 'id-token:write' IN job.effective_github_token_permissions\nRETURN p\nLIMIT 1000",
|
|
4
|
+
"description": "Returns workflow jobs whose calculated effective GITHUB_TOKEN permissions include id-token:write. These jobs can request GitHub OIDC tokens, though additional step analysis is needed to determine whether the token is actually used."
|
|
5
|
+
}
|
openhound_github-0.9.0/extension/saved_searches/workflow-jobs-with-observed-oidc-auth-steps.json
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "GitHub: Workflow Jobs with Observed OIDC Authentication Steps",
|
|
3
|
+
"query": "MATCH p=(repo:GH_Repository)-[:GH_Contains]->(:GH_Workflow)-[:GH_Contains]->(job:GH_WorkflowJob)-[:GH_Contains]->(step:GH_WorkflowStep)\nWHERE 'id-token:write' IN job.effective_github_token_permissions\nAND (\n step.action_slug = 'aws-actions/configure-aws-credentials'\n OR step.action_slug = 'azure/login'\n OR step.action_slug = 'Azure/login'\n OR step.action_slug = 'actions/deploy-pages'\n OR step.contents CONTAINS 'getIDToken'\n OR step.contents CONTAINS 'ACTIONS_ID_TOKEN_REQUEST_URL'\n OR step.contents CONTAINS 'ACTIONS_ID_TOKEN_REQUEST_TOKEN'\n)\nRETURN p\nLIMIT 1000",
|
|
4
|
+
"description": "Returns OIDC-capable workflow jobs with direct descendant steps that show likely OIDC token consumption, including common AWS, Azure, GitHub Pages, and direct token-request patterns. This is evidence of likely use, not a complete classifier for every possible OIDC consumer; reusable workflow callers may require following GH_CallsWorkflow to find the consuming steps."
|
|
5
|
+
}
|
|
@@ -512,6 +512,34 @@ class GithubLookup(LookupManager):
|
|
|
512
512
|
return None
|
|
513
513
|
return int(row[0])
|
|
514
514
|
|
|
515
|
+
@lru_cache
|
|
516
|
+
def repository_workflow_permissions(
|
|
517
|
+
self, repository_node_id: str
|
|
518
|
+
) -> tuple[str | None, bool | None] | None:
|
|
519
|
+
row = self._find_single_row(
|
|
520
|
+
f"""
|
|
521
|
+
SELECT
|
|
522
|
+
repository_default_workflow_permissions,
|
|
523
|
+
repository_can_approve_pull_request_reviews
|
|
524
|
+
FROM {self.schema}.workflows
|
|
525
|
+
WHERE repository_node_id = ?
|
|
526
|
+
LIMIT 1
|
|
527
|
+
""",
|
|
528
|
+
[repository_node_id],
|
|
529
|
+
)
|
|
530
|
+
if row is None:
|
|
531
|
+
return None
|
|
532
|
+
|
|
533
|
+
default_workflow_permissions, can_approve_pull_request_reviews = row
|
|
534
|
+
return (
|
|
535
|
+
default_workflow_permissions,
|
|
536
|
+
(
|
|
537
|
+
None
|
|
538
|
+
if can_approve_pull_request_reviews is None
|
|
539
|
+
else bool(can_approve_pull_request_reviews)
|
|
540
|
+
),
|
|
541
|
+
)
|
|
542
|
+
|
|
515
543
|
@lru_cache
|
|
516
544
|
def repository_default_branch_collected(self, repository_node_id: str) -> bool:
|
|
517
545
|
"""Return whether the repository's REST default branch was collected."""
|
|
@@ -41,6 +41,8 @@ class GHRepositoryProperties(GHNodeProperties):
|
|
|
41
41
|
environment_name: The name of the environment (GitHub organization).
|
|
42
42
|
actions_enabled: Whether GitHub Actions is enabled for this repository.
|
|
43
43
|
self_hosted_runners_enabled: Whether the repository may use self-hosted runners.
|
|
44
|
+
default_workflow_permissions: The repository's applicable default GITHUB_TOKEN workflow permissions.
|
|
45
|
+
can_approve_pull_request_reviews: Whether workflows may approve pull request reviews.
|
|
44
46
|
secret_scanning: Status of secret scanning (e.g., `enabled`, `disabled`).
|
|
45
47
|
branch_ruleset_count: Number of branch-targeted rulesets that apply to this repository.
|
|
46
48
|
has_branch_rulesets: Whether at least one branch-targeted ruleset applies to this repository.
|
|
@@ -87,6 +89,8 @@ class GHRepositoryProperties(GHNodeProperties):
|
|
|
87
89
|
environment_name: str | None = None
|
|
88
90
|
actions_enabled: bool | None = None
|
|
89
91
|
self_hosted_runners_enabled: bool | None = None
|
|
92
|
+
default_workflow_permissions: str | None = None
|
|
93
|
+
can_approve_pull_request_reviews: bool | None = None
|
|
90
94
|
secret_scanning: str | None = None
|
|
91
95
|
branch_ruleset_count: int | None = None
|
|
92
96
|
has_branch_rulesets: bool | None = None
|
|
@@ -226,6 +230,10 @@ class Repository(BaseAsset):
|
|
|
226
230
|
def as_node(self) -> GHNode:
|
|
227
231
|
rid = self.node_id
|
|
228
232
|
branch_ruleset_count = self._lookup.repository_branch_ruleset_count(rid)
|
|
233
|
+
workflow_permissions = self._lookup.repository_workflow_permissions(rid)
|
|
234
|
+
default_workflow_permissions, can_approve_pull_request_reviews = (
|
|
235
|
+
workflow_permissions if workflow_permissions else (None, None)
|
|
236
|
+
)
|
|
229
237
|
return GHNode(
|
|
230
238
|
kinds=[nk.REPOSITORY],
|
|
231
239
|
properties=GHRepositoryProperties(
|
|
@@ -256,6 +264,8 @@ class Repository(BaseAsset):
|
|
|
256
264
|
environmentid=self.org_node_id,
|
|
257
265
|
actions_enabled=self.actions_enabled,
|
|
258
266
|
self_hosted_runners_enabled=self.self_hosted_runners_enabled,
|
|
267
|
+
default_workflow_permissions=default_workflow_permissions,
|
|
268
|
+
can_approve_pull_request_reviews=can_approve_pull_request_reviews,
|
|
259
269
|
branch_ruleset_count=branch_ruleset_count,
|
|
260
270
|
has_branch_rulesets=(
|
|
261
271
|
branch_ruleset_count > 0
|
|
@@ -101,6 +101,137 @@ class RunsOnSelector(BaseModel):
|
|
|
101
101
|
is_dynamic: bool = False
|
|
102
102
|
|
|
103
103
|
|
|
104
|
+
GITHUB_TOKEN_PERMISSION_SCOPES = (
|
|
105
|
+
"actions",
|
|
106
|
+
"artifact-metadata",
|
|
107
|
+
"attestations",
|
|
108
|
+
"checks",
|
|
109
|
+
"code-quality",
|
|
110
|
+
"contents",
|
|
111
|
+
"deployments",
|
|
112
|
+
"discussions",
|
|
113
|
+
"id-token",
|
|
114
|
+
"issues",
|
|
115
|
+
"models",
|
|
116
|
+
"packages",
|
|
117
|
+
"pages",
|
|
118
|
+
"pull-requests",
|
|
119
|
+
"security-events",
|
|
120
|
+
"statuses",
|
|
121
|
+
"vulnerability-alerts",
|
|
122
|
+
)
|
|
123
|
+
READ_ONLY_GITHUB_TOKEN_PERMISSION_SCOPES = {"models", "vulnerability-alerts"}
|
|
124
|
+
WRITE_ONLY_GITHUB_TOKEN_PERMISSION_SCOPES = {"id-token"}
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def normalize_permission_declaration(value: Any) -> list[str] | None:
|
|
128
|
+
if value is None:
|
|
129
|
+
return None
|
|
130
|
+
|
|
131
|
+
if isinstance(value, str):
|
|
132
|
+
return [value]
|
|
133
|
+
|
|
134
|
+
if isinstance(value, list):
|
|
135
|
+
return [str(item) for item in value]
|
|
136
|
+
|
|
137
|
+
if isinstance(value, dict):
|
|
138
|
+
return [f"{key!s}:{item!s}" for key, item in value.items()]
|
|
139
|
+
|
|
140
|
+
return [str(value)]
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def _empty_github_token_permissions() -> dict[str, str]:
|
|
144
|
+
return {scope: "none" for scope in GITHUB_TOKEN_PERMISSION_SCOPES}
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def _all_github_token_permissions(
|
|
148
|
+
access: str, *, include_id_token: bool = True
|
|
149
|
+
) -> dict[str, str]:
|
|
150
|
+
permissions = _empty_github_token_permissions()
|
|
151
|
+
for scope in GITHUB_TOKEN_PERMISSION_SCOPES:
|
|
152
|
+
if scope in WRITE_ONLY_GITHUB_TOKEN_PERMISSION_SCOPES:
|
|
153
|
+
permissions[scope] = (
|
|
154
|
+
"write" if access == "write" and include_id_token else "none"
|
|
155
|
+
)
|
|
156
|
+
elif scope in READ_ONLY_GITHUB_TOKEN_PERMISSION_SCOPES:
|
|
157
|
+
permissions[scope] = "read"
|
|
158
|
+
else:
|
|
159
|
+
permissions[scope] = access
|
|
160
|
+
return permissions
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def _default_github_token_permissions(default_workflow_permissions: str | None):
|
|
164
|
+
if default_workflow_permissions is None:
|
|
165
|
+
return None
|
|
166
|
+
|
|
167
|
+
default = default_workflow_permissions.casefold()
|
|
168
|
+
if default == "read":
|
|
169
|
+
permissions = _empty_github_token_permissions()
|
|
170
|
+
permissions["contents"] = "read"
|
|
171
|
+
permissions["packages"] = "read"
|
|
172
|
+
return permissions
|
|
173
|
+
if default == "write":
|
|
174
|
+
return _all_github_token_permissions("write", include_id_token=False)
|
|
175
|
+
return None
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def _expand_permission_declaration(value: Any) -> dict[str, str] | None:
|
|
179
|
+
if value is None:
|
|
180
|
+
return None
|
|
181
|
+
|
|
182
|
+
if isinstance(value, str):
|
|
183
|
+
declaration = value.casefold()
|
|
184
|
+
if declaration == "read-all":
|
|
185
|
+
return _all_github_token_permissions("read")
|
|
186
|
+
if declaration == "write-all":
|
|
187
|
+
return _all_github_token_permissions("write")
|
|
188
|
+
return None
|
|
189
|
+
|
|
190
|
+
if isinstance(value, list):
|
|
191
|
+
if not value:
|
|
192
|
+
return _empty_github_token_permissions()
|
|
193
|
+
if len(value) == 1 and ":" not in str(value[0]):
|
|
194
|
+
return _expand_permission_declaration(str(value[0]))
|
|
195
|
+
|
|
196
|
+
normalized: dict[str, str] = {}
|
|
197
|
+
for item in value:
|
|
198
|
+
scope, separator, access = str(item).partition(":")
|
|
199
|
+
if not separator:
|
|
200
|
+
return None
|
|
201
|
+
normalized[scope] = access
|
|
202
|
+
value = normalized
|
|
203
|
+
|
|
204
|
+
if not isinstance(value, dict):
|
|
205
|
+
return None
|
|
206
|
+
|
|
207
|
+
permissions = _empty_github_token_permissions()
|
|
208
|
+
for raw_scope, raw_access in value.items():
|
|
209
|
+
scope = str(raw_scope).casefold()
|
|
210
|
+
permissions[scope] = str(raw_access).casefold()
|
|
211
|
+
return permissions
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
def resolve_effective_github_token_permissions(
|
|
215
|
+
default_workflow_permissions: str | None,
|
|
216
|
+
workflow_permissions: Any,
|
|
217
|
+
job_permissions: Any,
|
|
218
|
+
) -> list[str] | None:
|
|
219
|
+
permissions = _default_github_token_permissions(default_workflow_permissions)
|
|
220
|
+
|
|
221
|
+
for declaration in (workflow_permissions, job_permissions):
|
|
222
|
+
if declaration is None:
|
|
223
|
+
continue
|
|
224
|
+
expanded = _expand_permission_declaration(declaration)
|
|
225
|
+
if expanded is None:
|
|
226
|
+
return None
|
|
227
|
+
permissions = expanded
|
|
228
|
+
|
|
229
|
+
if permissions is None:
|
|
230
|
+
return None
|
|
231
|
+
|
|
232
|
+
return [f"{scope}:{access}" for scope, access in permissions.items()]
|
|
233
|
+
|
|
234
|
+
|
|
104
235
|
def parse_runs_on_selector(value: Any) -> RunsOnSelector:
|
|
105
236
|
"""Normalize a workflow job's runs-on declaration without losing group data."""
|
|
106
237
|
if value is None:
|
|
@@ -293,6 +424,7 @@ class GHWorkflowProperties(GHNodeProperties):
|
|
|
293
424
|
html_url: The GitHub web URL for the workflow file.
|
|
294
425
|
branch: The branch where the workflow file was found.
|
|
295
426
|
contents: The content of the workflow file.
|
|
427
|
+
workflow_permissions: Permissions declared at the workflow level.
|
|
296
428
|
query_repository: Query for repository.
|
|
297
429
|
query_jobs: Query for workflow jobs.
|
|
298
430
|
query_execution: Query for workflow executions.
|
|
@@ -310,6 +442,7 @@ class GHWorkflowProperties(GHNodeProperties):
|
|
|
310
442
|
html_url: str | None = None
|
|
311
443
|
branch: str | None = None
|
|
312
444
|
contents: str | None = None
|
|
445
|
+
workflow_permissions: list[str] | None = None
|
|
313
446
|
triggers: list[str] | None = None
|
|
314
447
|
trigger_dispatch_inputs: list[str] | None = None
|
|
315
448
|
is_pwn_requestable: bool = False
|
|
@@ -373,6 +506,8 @@ class Workflow(BaseAsset):
|
|
|
373
506
|
org_login: str
|
|
374
507
|
repository_name: str
|
|
375
508
|
repository_node_id: str
|
|
509
|
+
repository_default_workflow_permissions: str | None = None
|
|
510
|
+
repository_can_approve_pull_request_reviews: bool | None = None
|
|
376
511
|
|
|
377
512
|
@property
|
|
378
513
|
def org_node_id(self) -> str | None:
|
|
@@ -429,6 +564,13 @@ class Workflow(BaseAsset):
|
|
|
429
564
|
|
|
430
565
|
return [str(key) for key in inputs.keys()]
|
|
431
566
|
|
|
567
|
+
@property
|
|
568
|
+
def workflow_permissions(self) -> list[str] | None:
|
|
569
|
+
document = self.document
|
|
570
|
+
if not document:
|
|
571
|
+
return None
|
|
572
|
+
return normalize_permission_declaration(document.permissions)
|
|
573
|
+
|
|
432
574
|
@property
|
|
433
575
|
def pull_request_target_branches(self) -> list[str] | None:
|
|
434
576
|
document = self.document
|
|
@@ -571,6 +713,12 @@ class Workflow(BaseAsset):
|
|
|
571
713
|
"permissions": job.permissions
|
|
572
714
|
if job.permissions is not None
|
|
573
715
|
else document.permissions,
|
|
716
|
+
"job_permissions": job.permissions,
|
|
717
|
+
"effective_github_token_permissions": resolve_effective_github_token_permissions(
|
|
718
|
+
self.repository_default_workflow_permissions,
|
|
719
|
+
document.permissions,
|
|
720
|
+
job.permissions,
|
|
721
|
+
),
|
|
574
722
|
"uses_reusable": job.uses,
|
|
575
723
|
"workflow_node_id": self.node_id,
|
|
576
724
|
"repository_name": self.repository_name,
|
|
@@ -656,6 +804,7 @@ class Workflow(BaseAsset):
|
|
|
656
804
|
html_url=self.html_url,
|
|
657
805
|
branch=self.branch,
|
|
658
806
|
contents=self._decoded_contents,
|
|
807
|
+
workflow_permissions=self.workflow_permissions,
|
|
659
808
|
triggers=self.trigger_events,
|
|
660
809
|
trigger_dispatch_inputs=self.workflow_dispatch_inputs,
|
|
661
810
|
# is_pwn_requestable=self.is_pwn_requestable,
|
{openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/workflow_job.py
RENAMED
|
@@ -21,7 +21,11 @@ from openhound_github.graph import GHNode, GHNodeProperties
|
|
|
21
21
|
from openhound_github.kinds import edges as ek
|
|
22
22
|
from openhound_github.kinds import nodes as nk
|
|
23
23
|
from openhound_github.main import app
|
|
24
|
-
from openhound_github.models.workflow import
|
|
24
|
+
from openhound_github.models.workflow import (
|
|
25
|
+
normalize_permission_declaration,
|
|
26
|
+
parse_runs_on_selector,
|
|
27
|
+
resolve_effective_github_token_permissions,
|
|
28
|
+
)
|
|
25
29
|
|
|
26
30
|
TEMPLATE_RE = re.compile(r"\$\{\{\s*[^}]+?\s*\}\}")
|
|
27
31
|
|
|
@@ -44,7 +48,9 @@ class GHWorkflowJobProperties(GHNodeProperties):
|
|
|
44
48
|
is_self_hosted: Whether the job targets self-hosted runners.
|
|
45
49
|
container: The optional container configuration.
|
|
46
50
|
environment: The deployment environment name.
|
|
47
|
-
permissions:
|
|
51
|
+
permissions: Applicable declared workflow or job permissions after job-over-workflow precedence.
|
|
52
|
+
job_permissions: Optional permissions declared at the job level; absent when the job has no declaration.
|
|
53
|
+
effective_github_token_permissions: Calculated GITHUB_TOKEN permissions after repository defaults and declarations are applied.
|
|
48
54
|
uses_reusable: The reusable workflow reference used by this job.
|
|
49
55
|
workflow_node_id: The parent workflow node ID.
|
|
50
56
|
repository_name: The containing repository name.
|
|
@@ -65,6 +71,8 @@ class GHWorkflowJobProperties(GHNodeProperties):
|
|
|
65
71
|
container: str | None = None
|
|
66
72
|
environment: str | None = None
|
|
67
73
|
permissions: list[str] | None = None
|
|
74
|
+
job_permissions: list[str] | None = None
|
|
75
|
+
effective_github_token_permissions: list[str] | None = None
|
|
68
76
|
uses_reusable: str | None = None
|
|
69
77
|
workflow_node_id: str | None = None
|
|
70
78
|
repository_name: str | None = None
|
|
@@ -182,6 +190,8 @@ class WorkflowJob(BaseAsset):
|
|
|
182
190
|
container: str | None = None
|
|
183
191
|
environment: str | None = None
|
|
184
192
|
permissions: list[str] | None = None
|
|
193
|
+
job_permissions: list[str] | None = None
|
|
194
|
+
effective_github_token_permissions: list[str] | None = None
|
|
185
195
|
uses_reusable: str | None = None
|
|
186
196
|
dependency_node_ids: list[str] = Field(default_factory=list)
|
|
187
197
|
secret_references: list[WorkflowReference] = Field(default_factory=list)
|
|
@@ -191,22 +201,15 @@ class WorkflowJob(BaseAsset):
|
|
|
191
201
|
def org_node_id(self) -> str | None:
|
|
192
202
|
return self._lookup.org_id_for_login(self.org_login)
|
|
193
203
|
|
|
194
|
-
@field_validator(
|
|
204
|
+
@field_validator(
|
|
205
|
+
"permissions",
|
|
206
|
+
"job_permissions",
|
|
207
|
+
"effective_github_token_permissions",
|
|
208
|
+
mode="before",
|
|
209
|
+
)
|
|
195
210
|
@classmethod
|
|
196
211
|
def normalize_permissions(cls, value: Any) -> list[str] | None:
|
|
197
|
-
|
|
198
|
-
return None
|
|
199
|
-
|
|
200
|
-
if isinstance(value, str):
|
|
201
|
-
return [value]
|
|
202
|
-
|
|
203
|
-
if isinstance(value, list):
|
|
204
|
-
return [str(item) for item in value]
|
|
205
|
-
|
|
206
|
-
if isinstance(value, dict):
|
|
207
|
-
return [f"{str(key)}:{str(value)}" for key, value in value.items()]
|
|
208
|
-
|
|
209
|
-
return [str(value)]
|
|
212
|
+
return normalize_permission_declaration(value)
|
|
210
213
|
|
|
211
214
|
@model_validator(mode="before")
|
|
212
215
|
@classmethod
|
|
@@ -233,6 +236,20 @@ class WorkflowJob(BaseAsset):
|
|
|
233
236
|
str(label).casefold() for label in (self.runs_on_labels or self.runs_on or [])
|
|
234
237
|
}
|
|
235
238
|
|
|
239
|
+
@property
|
|
240
|
+
def calculated_effective_github_token_permissions(self) -> list[str] | None:
|
|
241
|
+
workflow_permissions = self._lookup.repository_workflow_permissions(
|
|
242
|
+
self.repository_node_id
|
|
243
|
+
)
|
|
244
|
+
default_workflow_permissions = (
|
|
245
|
+
workflow_permissions[0] if workflow_permissions else None
|
|
246
|
+
)
|
|
247
|
+
return resolve_effective_github_token_permissions(
|
|
248
|
+
default_workflow_permissions,
|
|
249
|
+
self.permissions,
|
|
250
|
+
None,
|
|
251
|
+
)
|
|
252
|
+
|
|
236
253
|
@property
|
|
237
254
|
def as_node(self) -> GHNode:
|
|
238
255
|
jid = self.node_id
|
|
@@ -251,6 +268,8 @@ class WorkflowJob(BaseAsset):
|
|
|
251
268
|
container=self.container,
|
|
252
269
|
environment=self.environment,
|
|
253
270
|
permissions=self.permissions,
|
|
271
|
+
job_permissions=self.job_permissions,
|
|
272
|
+
effective_github_token_permissions=self.calculated_effective_github_token_permissions,
|
|
254
273
|
uses_reusable=self.uses_reusable,
|
|
255
274
|
workflow_node_id=self.workflow_node_id,
|
|
256
275
|
repository_name=self.repository_name,
|
{openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/resources/organization.py
RENAMED
|
@@ -122,6 +122,9 @@ class SourceContext:
|
|
|
122
122
|
actions_permissions_cache: dict[str, dict[str, Any]] = field(default_factory=dict)
|
|
123
123
|
runner_permissions_cache: dict[str, dict[str, Any]] = field(default_factory=dict)
|
|
124
124
|
workflow_permissions_cache: dict[str, dict[str, Any]] = field(default_factory=dict)
|
|
125
|
+
repository_workflow_permissions_cache: dict[str, dict[str, Any]] = field(
|
|
126
|
+
default_factory=dict
|
|
127
|
+
)
|
|
125
128
|
|
|
126
129
|
|
|
127
130
|
class RepositoryRoleCache:
|
|
@@ -230,6 +233,19 @@ def _workflow_permissions(
|
|
|
230
233
|
)
|
|
231
234
|
|
|
232
235
|
|
|
236
|
+
def _repository_workflow_permissions(
|
|
237
|
+
ctx: SourceContext, client: RESTClient, repository_full_name: str
|
|
238
|
+
) -> dict[str, Any]:
|
|
239
|
+
cache_key = repository_full_name.casefold()
|
|
240
|
+
if cache_key not in ctx.repository_workflow_permissions_cache:
|
|
241
|
+
with ctx.cache_lock:
|
|
242
|
+
if cache_key not in ctx.repository_workflow_permissions_cache:
|
|
243
|
+
ctx.repository_workflow_permissions_cache[cache_key] = client.get(
|
|
244
|
+
f"/repos/{repository_full_name}/actions/permissions/workflow"
|
|
245
|
+
).json()
|
|
246
|
+
return ctx.repository_workflow_permissions_cache[cache_key]
|
|
247
|
+
|
|
248
|
+
|
|
233
249
|
def _rest_teams_for_org(
|
|
234
250
|
ctx: SourceContext, client: RESTClient, org_name: str
|
|
235
251
|
) -> list[dict[str, Any]]:
|
|
@@ -1360,7 +1376,10 @@ def workflows(repo: Repository, ctx: SourceContext):
|
|
|
1360
1376
|
|
|
1361
1377
|
@app.defer
|
|
1362
1378
|
def _workflow_file_contents(
|
|
1363
|
-
client: RESTClient,
|
|
1379
|
+
client: RESTClient,
|
|
1380
|
+
repo: Repository,
|
|
1381
|
+
workflow: dict[str, Any],
|
|
1382
|
+
workflow_permissions: dict[str, Any],
|
|
1364
1383
|
) -> dict | None:
|
|
1365
1384
|
path = workflow.get("path")
|
|
1366
1385
|
if not path:
|
|
@@ -1382,15 +1401,28 @@ def workflows(repo: Repository, ctx: SourceContext):
|
|
|
1382
1401
|
"repository_name": repo.name,
|
|
1383
1402
|
"repository_node_id": repo.node_id,
|
|
1384
1403
|
"org_login": repo.org_login,
|
|
1404
|
+
"repository_default_workflow_permissions": workflow_permissions.get(
|
|
1405
|
+
"default_workflow_permissions"
|
|
1406
|
+
),
|
|
1407
|
+
"repository_can_approve_pull_request_reviews": workflow_permissions.get(
|
|
1408
|
+
"can_approve_pull_request_reviews"
|
|
1409
|
+
),
|
|
1385
1410
|
}
|
|
1386
1411
|
|
|
1387
1412
|
client = _client_for_org(ctx, repo.org_login)
|
|
1413
|
+
workflow_permissions: dict[str, Any] | None = None
|
|
1388
1414
|
for page in client.paginate(
|
|
1389
1415
|
f"/repos/{repo.full_name}/actions/workflows", params={"per_page": 100}
|
|
1390
1416
|
):
|
|
1391
1417
|
for workflow in page:
|
|
1392
1418
|
if workflow.get("state") == "active":
|
|
1393
|
-
|
|
1419
|
+
if workflow_permissions is None:
|
|
1420
|
+
workflow_permissions = _repository_workflow_permissions(
|
|
1421
|
+
ctx, client, repo.full_name
|
|
1422
|
+
)
|
|
1423
|
+
yield _workflow_file_contents(
|
|
1424
|
+
client, repo, workflow, workflow_permissions
|
|
1425
|
+
)
|
|
1394
1426
|
|
|
1395
1427
|
|
|
1396
1428
|
@app.transformer(name="workflow_jobs", columns=WorkflowJob, parallelized=True)
|
|
@@ -177,6 +177,9 @@ class SourceContext:
|
|
|
177
177
|
actions_permissions_cache: dict[str, dict[str, Any]] = field(default_factory=dict)
|
|
178
178
|
runner_permissions_cache: dict[str, dict[str, Any]] = field(default_factory=dict)
|
|
179
179
|
workflow_permissions_cache: dict[str, dict[str, Any]] = field(default_factory=dict)
|
|
180
|
+
repository_workflow_permissions_cache: dict[str, dict[str, Any]] = field(
|
|
181
|
+
default_factory=dict
|
|
182
|
+
)
|
|
180
183
|
|
|
181
184
|
@property
|
|
182
185
|
def org_names(self) -> list[str]:
|
|
@@ -172,6 +172,13 @@ def ensure_optional_input_tables(
|
|
|
172
172
|
labels JSON,
|
|
173
173
|
repository_node_id VARCHAR
|
|
174
174
|
);
|
|
175
|
+
CREATE TABLE IF NOT EXISTS {schema}.workflows (
|
|
176
|
+
name VARCHAR,
|
|
177
|
+
path VARCHAR,
|
|
178
|
+
repository_node_id VARCHAR,
|
|
179
|
+
repository_default_workflow_permissions VARCHAR,
|
|
180
|
+
repository_can_approve_pull_request_reviews BOOLEAN
|
|
181
|
+
);
|
|
175
182
|
""")
|
|
176
183
|
con.execute(f"""
|
|
177
184
|
ALTER TABLE {schema}.branches
|
|
@@ -387,6 +394,17 @@ def ensure_optional_input_tables(
|
|
|
387
394
|
ADD COLUMN IF NOT EXISTS labels JSON;
|
|
388
395
|
ALTER TABLE {schema}.repo_runners
|
|
389
396
|
ADD COLUMN IF NOT EXISTS repository_node_id VARCHAR;
|
|
397
|
+
|
|
398
|
+
ALTER TABLE {schema}.workflows
|
|
399
|
+
ADD COLUMN IF NOT EXISTS name VARCHAR;
|
|
400
|
+
ALTER TABLE {schema}.workflows
|
|
401
|
+
ADD COLUMN IF NOT EXISTS path VARCHAR;
|
|
402
|
+
ALTER TABLE {schema}.workflows
|
|
403
|
+
ADD COLUMN IF NOT EXISTS repository_node_id VARCHAR;
|
|
404
|
+
ALTER TABLE {schema}.workflows
|
|
405
|
+
ADD COLUMN IF NOT EXISTS repository_default_workflow_permissions VARCHAR;
|
|
406
|
+
ALTER TABLE {schema}.workflows
|
|
407
|
+
ADD COLUMN IF NOT EXISTS repository_can_approve_pull_request_reviews BOOLEAN;
|
|
390
408
|
""")
|
|
391
409
|
|
|
392
410
|
# TODO:
|