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.
Files changed (421) hide show
  1. {openhound_github-0.8.0 → openhound_github-0.9.0}/PKG-INFO +1 -1
  2. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_CanPwnRequest.md +1 -1
  3. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_Repository.md +4 -0
  4. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_Workflow.md +3 -0
  5. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_WorkflowJob.md +5 -1
  6. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/README.md +17 -13
  7. openhound_github-0.9.0/extension/saved_searches/workflow-jobs-with-broad-token-write-permissions.json +5 -0
  8. openhound_github-0.9.0/extension/saved_searches/workflow-jobs-with-id-token-write-on-self-hosted-runners.json +5 -0
  9. openhound_github-0.9.0/extension/saved_searches/workflow-jobs-with-id-token-write.json +5 -0
  10. openhound_github-0.9.0/extension/saved_searches/workflow-jobs-with-observed-oidc-auth-steps.json +5 -0
  11. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/lookup.py +28 -0
  12. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/repository.py +10 -0
  13. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/workflow.py +149 -0
  14. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/workflow_job.py +35 -16
  15. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/resources/organization.py +34 -2
  16. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/source.py +3 -0
  17. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/transforms.py +18 -0
  18. {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_repository_rulesets.py +24 -0
  19. {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_workflow_model.py +187 -1
  20. openhound_github-0.9.0/tests/test_workflow_resources.py +98 -0
  21. {openhound_github-0.8.0 → openhound_github-0.9.0}/.github/CODE_OF_CONDUCT.md +0 -0
  22. {openhound_github-0.8.0 → openhound_github-0.9.0}/.github/CONTRIBUTING.md +0 -0
  23. {openhound_github-0.8.0 → openhound_github-0.9.0}/.github/GOVERNANCE.md +0 -0
  24. {openhound_github-0.8.0 → openhound_github-0.9.0}/.github/GitHub-COC-Header.png +0 -0
  25. {openhound_github-0.8.0 → openhound_github-0.9.0}/.github/GitHub-CONTRIB-Header.png +0 -0
  26. {openhound_github-0.8.0 → openhound_github-0.9.0}/.github/GitHub-GOV-Header.png +0 -0
  27. {openhound_github-0.8.0 → openhound_github-0.9.0}/.github/GitHub-Header.png +0 -0
  28. {openhound_github-0.8.0 → openhound_github-0.9.0}/.github/GitHub-LIC-Header.png +0 -0
  29. {openhound_github-0.8.0 → openhound_github-0.9.0}/.github/GitHub-SEC-Header.png +0 -0
  30. {openhound_github-0.8.0 → openhound_github-0.9.0}/.github/SECURITY.md +0 -0
  31. {openhound_github-0.8.0 → openhound_github-0.9.0}/.github/SO-Dark.svg +0 -0
  32. {openhound_github-0.8.0 → openhound_github-0.9.0}/.github/SO-FOSS-Dark.svg +0 -0
  33. {openhound_github-0.8.0 → openhound_github-0.9.0}/.github/SO-FOSS-Light.svg +0 -0
  34. {openhound_github-0.8.0 → openhound_github-0.9.0}/.github/SO-Light.svg +0 -0
  35. {openhound_github-0.8.0 → openhound_github-0.9.0}/.github/workflows/publish.yml +0 -0
  36. {openhound_github-0.8.0 → openhound_github-0.9.0}/.github/workflows/release-on-merge.yml +0 -0
  37. {openhound_github-0.8.0 → openhound_github-0.9.0}/.github/workflows/validate-branch.yml +0 -0
  38. {openhound_github-0.8.0 → openhound_github-0.9.0}/.gitignore +0 -0
  39. {openhound_github-0.8.0 → openhound_github-0.9.0}/.gitmodules +0 -0
  40. {openhound_github-0.8.0 → openhound_github-0.9.0}/.pre-commit-config.yaml +0 -0
  41. {openhound_github-0.8.0 → openhound_github-0.9.0}/LICENSE.md +0 -0
  42. {openhound_github-0.8.0 → openhound_github-0.9.0}/README.md +0 -0
  43. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_AddAssignee.md +0 -0
  44. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_AddCollaborator.md +0 -0
  45. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_AddLabel.md +0 -0
  46. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_AddMember.md +0 -0
  47. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_AdminTo.md +0 -0
  48. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ApprovesDeploymentTo.md +0 -0
  49. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_AssignedTo.md +0 -0
  50. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_BypassBranchProtection.md +0 -0
  51. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_BypassPullRequestAllowances.md +0 -0
  52. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_CallsWorkflow.md +0 -0
  53. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_CanAccess.md +0 -0
  54. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_CanAssumeIdentity.md +0 -0
  55. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_CanCreateBranch.md +0 -0
  56. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_CanCreateEnvironment.md +0 -0
  57. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_CanCreateInternalRepositories.md +0 -0
  58. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_CanCreatePrivateRepositories.md +0 -0
  59. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_CanCreatePublicRepositories.md +0 -0
  60. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_CanCreateRepositories.md +0 -0
  61. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_CanCreateRepositoryWithRunnerAccess.md +0 -0
  62. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_CanDeployToEnvironment.md +0 -0
  63. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_CanEditEnvironment.md +0 -0
  64. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_CanEditProtection.md +0 -0
  65. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_CanReadSecret.md +0 -0
  66. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_CanReadSecretScanningAlert.md +0 -0
  67. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_CanUseRunner.md +0 -0
  68. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_CanWriteBranch.md +0 -0
  69. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_CloseDiscussion.md +0 -0
  70. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_CloseIssue.md +0 -0
  71. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ClosePullRequest.md +0 -0
  72. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_Contains.md +0 -0
  73. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ConvertIssuesToDiscussions.md +0 -0
  74. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_CreateDiscussionCategory.md +0 -0
  75. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_CreateEnterpriseOrganizations.md +0 -0
  76. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_CreateRepository.md +0 -0
  77. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_CreateSoloMergeQueueEntry.md +0 -0
  78. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_CreateTag.md +0 -0
  79. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_CreateTeam.md +0 -0
  80. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_DeleteAlertsCodeScanning.md +0 -0
  81. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_DeleteDiscussion.md +0 -0
  82. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_DeleteDiscussionComment.md +0 -0
  83. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_DeleteIssue.md +0 -0
  84. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_DeleteTag.md +0 -0
  85. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_DependsOn.md +0 -0
  86. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_DeploysTo.md +0 -0
  87. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_EditCategoryOnDiscussion.md +0 -0
  88. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_EditDiscussionCategory.md +0 -0
  89. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_EditDiscussionComment.md +0 -0
  90. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_EditEnterpriseCustomPropertiesForOrganizations.md +0 -0
  91. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_EditRepoAnnouncementBanners.md +0 -0
  92. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_EditRepoCustomPropertiesValues.md +0 -0
  93. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_EditRepoMetadata.md +0 -0
  94. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_EditRepoProtections.md +0 -0
  95. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_HasBaseRole.md +0 -0
  96. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_HasExternalIdentity.md +0 -0
  97. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_HasMember.md +0 -0
  98. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_HasPersonalAccessToken.md +0 -0
  99. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_HasPersonalAccessTokenRequest.md +0 -0
  100. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_HasRole.md +0 -0
  101. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_HasRunner.md +0 -0
  102. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_HasSamlIdentityProvider.md +0 -0
  103. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_HasSecret.md +0 -0
  104. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_HasVariable.md +0 -0
  105. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_InheritedFrom.md +0 -0
  106. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_InstalledAs.md +0 -0
  107. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_InviteMember.md +0 -0
  108. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_IsEligibleFor.md +0 -0
  109. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_JumpMergeQueue.md +0 -0
  110. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ManageDeployKeys.md +0 -0
  111. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ManageDiscussionBadges.md +0 -0
  112. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ManageEnterpriseAdmins.md +0 -0
  113. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ManageEnterpriseIdentityProvider.md +0 -0
  114. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ManageEnterpriseMembers.md +0 -0
  115. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ManageEnterpriseOrganizationAdmins.md +0 -0
  116. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ManageEnterpriseOrganizations.md +0 -0
  117. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ManageEnterpriseReferrals.md +0 -0
  118. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ManageEnterpriseTeams.md +0 -0
  119. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ManageOrganizationWebhooks.md +0 -0
  120. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ManageRepoSecurityProducts.md +0 -0
  121. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ManageSecurityProducts.md +0 -0
  122. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ManageSettingsMergeTypes.md +0 -0
  123. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ManageSettingsPages.md +0 -0
  124. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ManageSettingsProjects.md +0 -0
  125. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ManageSettingsWiki.md +0 -0
  126. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ManageTopics.md +0 -0
  127. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ManageWebhooks.md +0 -0
  128. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_MapsToUser.md +0 -0
  129. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_MarkAsDuplicate.md +0 -0
  130. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_MatchesEnvironmentPolicy.md +0 -0
  131. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_MemberOf.md +0 -0
  132. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_OrgBypassCodeScanningDismissalRequests.md +0 -0
  133. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_OrgBypassSecretScanningClosureRequests.md +0 -0
  134. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_OrgReviewAndManageSecretScanningBypassRequests.md +0 -0
  135. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_OrgReviewAndManageSecretScanningClosureRequests.md +0 -0
  136. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_Owns.md +0 -0
  137. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ProtectedBy.md +0 -0
  138. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_PushProtectedBranch.md +0 -0
  139. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ReadCodeScanning.md +0 -0
  140. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ReadEnterpriseAuditLog.md +0 -0
  141. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ReadEnterpriseDomainVerification.md +0 -0
  142. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ReadEnterpriseMembers.md +0 -0
  143. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ReadEnterpriseOrgProjects.md +0 -0
  144. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ReadEnterpriseOrganizationAdmin.md +0 -0
  145. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ReadOrganizationActionsUsageMetrics.md +0 -0
  146. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ReadOrganizationCustomOrgRole.md +0 -0
  147. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ReadOrganizationCustomRepoRole.md +0 -0
  148. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ReadRepoContents.md +0 -0
  149. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_RemoveAssignee.md +0 -0
  150. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_RemoveLabel.md +0 -0
  151. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ReopenDiscussion.md +0 -0
  152. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ReopenIssue.md +0 -0
  153. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ReopenPullRequest.md +0 -0
  154. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_RequestPrReview.md +0 -0
  155. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ResolveDependabotAlerts.md +0 -0
  156. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ResolveSecretScanningAlerts.md +0 -0
  157. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_RestrictionsCanPush.md +0 -0
  158. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_RunOrgMigration.md +0 -0
  159. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_RunsOn.md +0 -0
  160. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_SetEnterpriseInteractionLimits.md +0 -0
  161. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_SetInteractionLimits.md +0 -0
  162. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_SetIssueType.md +0 -0
  163. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_SetMilestone.md +0 -0
  164. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_SetSocialPreview.md +0 -0
  165. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_SyncedTo.md +0 -0
  166. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ToggleDiscussionAnswer.md +0 -0
  167. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ToggleDiscussionCommentMinimize.md +0 -0
  168. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_TransferRepository.md +0 -0
  169. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_UsesSecret.md +0 -0
  170. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_UsesVariable.md +0 -0
  171. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ValidToken.md +0 -0
  172. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ViewDependabotAlerts.md +0 -0
  173. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ViewEnterpriseActionsUsageMetrics.md +0 -0
  174. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ViewEnterpriseBilling.md +0 -0
  175. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ViewEnterpriseSecretScanningAlerts.md +0 -0
  176. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_ViewSecretScanningAlerts.md +0 -0
  177. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_WriteCodeScanning.md +0 -0
  178. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_WriteEnterpriseActionsPolicies.md +0 -0
  179. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_WriteEnterpriseBilling.md +0 -0
  180. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_WriteEnterprisePersonalAccessTokenPolicies.md +0 -0
  181. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_WriteEnterpriseSso.md +0 -0
  182. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_WriteEnterpriseTeamMembers.md +0 -0
  183. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_WriteOrganizationActionsSecrets.md +0 -0
  184. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_WriteOrganizationActionsSettings.md +0 -0
  185. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_WriteOrganizationActionsVariables.md +0 -0
  186. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_WriteOrganizationCustomOrgRole.md +0 -0
  187. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_WriteOrganizationCustomRepoRole.md +0 -0
  188. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_WriteOrganizationNetworkConfigurations.md +0 -0
  189. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_WriteRepoContents.md +0 -0
  190. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/edges/GH_WriteRepoPullRequests.md +0 -0
  191. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_App.md +0 -0
  192. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_AppInstallation.md +0 -0
  193. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_Branch.md +0 -0
  194. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_BranchProtectionRule.md +0 -0
  195. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_Enterprise.md +0 -0
  196. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_EnterpriseManagedUser.md +0 -0
  197. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_EnterpriseRole.md +0 -0
  198. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_EnterpriseRunner.md +0 -0
  199. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_EnterpriseRunnerGroup.md +0 -0
  200. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_EnterpriseTeam.md +0 -0
  201. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_Environment.md +0 -0
  202. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_EnvironmentBranchPolicy.md +0 -0
  203. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_EnvironmentSecret.md +0 -0
  204. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_EnvironmentVariable.md +0 -0
  205. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_ExternalIdentity.md +0 -0
  206. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_OrgRole.md +0 -0
  207. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_OrgRunner.md +0 -0
  208. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_OrgRunnerGroup.md +0 -0
  209. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_OrgSecret.md +0 -0
  210. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_OrgVariable.md +0 -0
  211. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_Organization.md +0 -0
  212. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_PersonalAccessToken.md +0 -0
  213. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_PersonalAccessTokenRequest.md +0 -0
  214. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_RepoRole.md +0 -0
  215. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_RepoRunner.md +0 -0
  216. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_RepoSecret.md +0 -0
  217. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_RepoVariable.md +0 -0
  218. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_Runner.md +0 -0
  219. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_RunnerGroup.md +0 -0
  220. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_SamlIdentityProvider.md +0 -0
  221. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_Secret.md +0 -0
  222. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_SecretScanningAlert.md +0 -0
  223. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_Team.md +0 -0
  224. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_TeamRole.md +0 -0
  225. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_User.md +0 -0
  226. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_Variable.md +0 -0
  227. {openhound_github-0.8.0 → openhound_github-0.9.0}/descriptions/nodes/GH_WorkflowStep.md +0 -0
  228. {openhound_github-0.8.0 → openhound_github-0.9.0}/docs/og-docs.json +0 -0
  229. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/privilege_zone_rules/t0-all-repo-admin-role.json +0 -0
  230. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/privilege_zone_rules/t0-app-installations-all-repos.json +0 -0
  231. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/privilege_zone_rules/t0-apps-all-repos.json +0 -0
  232. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/privilege_zone_rules/t0-enterprise-owners-role.json +0 -0
  233. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/privilege_zone_rules/t0-external-identities-owners.json +0 -0
  234. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/privilege_zone_rules/t0-organizations.json +0 -0
  235. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/privilege_zone_rules/t0-owner-users.json +0 -0
  236. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/privilege_zone_rules/t0-owners-role.json +0 -0
  237. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/privilege_zone_rules/t0-pats-all-repos.json +0 -0
  238. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/privilege_zone_rules/t0-privilege-escalation-roles.json +0 -0
  239. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/privilege_zone_rules/t0-privilege-escalation-users.json +0 -0
  240. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/privilege_zone_rules/t0-saml-identity-providers.json +0 -0
  241. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/actions-sha-pinning-not-required.json +0 -0
  242. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/active-leaked-secrets.json +0 -0
  243. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/advanced-security-disabled-new-repos.json +0 -0
  244. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/all-actions-allowed.json +0 -0
  245. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/app-installations-all-repos.json +0 -0
  246. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/branch-protection-admins-not-enforced.json +0 -0
  247. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/branch-protection-deletions-allowed.json +0 -0
  248. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/branch-protection-force-pushes.json +0 -0
  249. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/branch-protection-no-code-owner-reviews.json +0 -0
  250. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/branch-protection-no-pr-reviews.json +0 -0
  251. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/branch-protection-no-status-checks.json +0 -0
  252. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/branch-protection-self-approval.json +0 -0
  253. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/branch-protection-stale-reviews.json +0 -0
  254. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/bypass-pr-requirements.json +0 -0
  255. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/dangerous-branch-perms.json +0 -0
  256. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/default-repository-permissions.json +0 -0
  257. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/demo-sso-to-cloud-round-trip.json +0 -0
  258. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/dependabot-alerts-disabled-new-repos.json +0 -0
  259. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/dependabot-updates-disabled-new-repos.json +0 -0
  260. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/dependency-graph-disabled-new-repos.json +0 -0
  261. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/environments-admin-bypass.json +0 -0
  262. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/expired-pats.json +0 -0
  263. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/external-identities-without-scim.json +0 -0
  264. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/github-to-azure-identity.json +0 -0
  265. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/global-repo-perms.json +0 -0
  266. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/hybrid-identities.json +0 -0
  267. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/members-can-change-repo-visibility.json +0 -0
  268. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/members-can-create-pages.json +0 -0
  269. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/members-can-create-public-repos.json +0 -0
  270. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/members-can-delete-repos.json +0 -0
  271. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/members-can-fork-private-repos.json +0 -0
  272. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/members-can-invite-outside-collaborators.json +0 -0
  273. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/org-owners.json +0 -0
  274. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/orgs-without-2fa.json +0 -0
  275. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/pats-all-repo-access.json +0 -0
  276. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/pending-pat-requests.json +0 -0
  277. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/private-repos-forking-allowed.json +0 -0
  278. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/privileged-custom-org-roles.json +0 -0
  279. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/privileged-hybrid-identities.json +0 -0
  280. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/public-repos.json +0 -0
  281. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/push-protection-disabled-new-repos.json +0 -0
  282. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/push-to-protected-branches.json +0 -0
  283. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/repos-secret-scanning-disabled.json +0 -0
  284. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/repos-vulnerable-to-workflow-secret-exfil.json +0 -0
  285. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/repository-workflows.json +0 -0
  286. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/saml-configuration.json +0 -0
  287. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/secret-scanning-alerts.json +0 -0
  288. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/secret-scanning-disabled-new-repos.json +0 -0
  289. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/secrets-reachable-by-user.json +0 -0
  290. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/team-membership-admin.json +0 -0
  291. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/team-structure.json +0 -0
  292. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/unprotected-branches.json +0 -0
  293. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/unprotected-default-branch-with-workflow.json +0 -0
  294. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/unprotected-default-branches.json +0 -0
  295. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/saved_searches/web-commit-signoff-not-required.json +0 -0
  296. {openhound_github-0.8.0 → openhound_github-0.9.0}/extension/schema.json +0 -0
  297. {openhound_github-0.8.0 → openhound_github-0.9.0}/justfile +0 -0
  298. {openhound_github-0.8.0 → openhound_github-0.9.0}/pyproject.toml +0 -0
  299. {openhound_github-0.8.0 → openhound_github-0.9.0}/scripts/generate_gh_description_docs.py +0 -0
  300. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/main.py +0 -0
  301. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/__init__.py +0 -0
  302. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/auth.py +0 -0
  303. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/extension.yaml +0 -0
  304. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/github_rest_client.py +0 -0
  305. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/github_retry.py +0 -0
  306. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/graph.py +0 -0
  307. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/graphql.py +0 -0
  308. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/helpers.py +0 -0
  309. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/kinds/edges.py +0 -0
  310. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/kinds/nodes.py +0 -0
  311. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/main.py +0 -0
  312. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/__init__.py +0 -0
  313. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/actions_permission.py +0 -0
  314. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/app_installation.py +0 -0
  315. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/branch.py +0 -0
  316. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/branch_pr_bypass_allowance.py +0 -0
  317. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/branch_protection_rule.py +0 -0
  318. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/branch_push_allowance.py +0 -0
  319. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/enterprise.py +0 -0
  320. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/enterprise_admin.py +0 -0
  321. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/enterprise_helpers.py +0 -0
  322. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/enterprise_managed_user.py +0 -0
  323. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/enterprise_member.py +0 -0
  324. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/enterprise_organization.py +0 -0
  325. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/enterprise_role.py +0 -0
  326. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/enterprise_role_team.py +0 -0
  327. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/enterprise_role_user.py +0 -0
  328. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/enterprise_team.py +0 -0
  329. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/enterprise_team_member.py +0 -0
  330. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/enterprise_team_organization.py +0 -0
  331. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/enterprise_team_role.py +0 -0
  332. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/enterprise_user.py +0 -0
  333. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/env_secret.py +0 -0
  334. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/env_variable.py +0 -0
  335. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/environment.py +0 -0
  336. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/environment_branch_policy.py +0 -0
  337. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/external_identity.py +0 -0
  338. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/org.py +0 -0
  339. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/org_role.py +0 -0
  340. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/org_role_member.py +0 -0
  341. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/org_role_team.py +0 -0
  342. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/org_secret.py +0 -0
  343. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/org_variable.py +0 -0
  344. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/personal_access_token.py +0 -0
  345. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/personal_access_token_access.py +0 -0
  346. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/personal_access_token_request.py +0 -0
  347. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/projected_enterprise_team.py +0 -0
  348. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/repo_role_assignment.py +0 -0
  349. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/repository_role.py +0 -0
  350. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/repository_secret.py +0 -0
  351. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/repository_variable.py +0 -0
  352. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/runner.py +0 -0
  353. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/saml_assertion_consumer_service.py +0 -0
  354. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/saml_helpers.py +0 -0
  355. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/saml_issuer.py +0 -0
  356. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/saml_provider.py +0 -0
  357. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/saml_service_provider.py +0 -0
  358. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/scim_user.py +0 -0
  359. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/secret_scanning_alert.py +0 -0
  360. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/team.py +0 -0
  361. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/team_member.py +0 -0
  362. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/team_role.py +0 -0
  363. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/user.py +0 -0
  364. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/models/workflow_step.py +0 -0
  365. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/resources/__init__.py +0 -0
  366. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/resources/enterprise.py +0 -0
  367. {openhound_github-0.8.0 → openhound_github-0.9.0}/src/openhound_github/runner_ids.py +0 -0
  368. {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_app_auth.py +0 -0
  369. {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_branch_collection_gate.py +0 -0
  370. {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_branch_protection_traversability.py +0 -0
  371. {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_data/api/actions-permissions.json +0 -0
  372. {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_data/api/actionsecrets.json +0 -0
  373. {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_data/api/app.json +0 -0
  374. {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_data/api/appinstalls.json +0 -0
  375. {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_data/api/branch-policies.json +0 -0
  376. {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_data/api/branch-prot-rules.json +0 -0
  377. {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_data/api/branches.json +0 -0
  378. {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_data/api/custom-roles.json +0 -0
  379. {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_data/api/environments.json +0 -0
  380. {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_data/api/org-pat-request.json +0 -0
  381. {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_data/api/org-pat.json +0 -0
  382. {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_data/api/org-role-teams.json +0 -0
  383. {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_data/api/org-role-users.json +0 -0
  384. {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_data/api/org-roles.json +0 -0
  385. {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_data/api/org.json +0 -0
  386. {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_data/api/pat-repositories.json +0 -0
  387. {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_data/api/repo-collaborators.json +0 -0
  388. {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_data/api/repo-teams.json +0 -0
  389. {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_data/api/repositories.json +0 -0
  390. {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_data/api/scimusers.json +0 -0
  391. {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_data/api/secrets.json +0 -0
  392. {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_data/api/secretscanningalert.json +0 -0
  393. {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_data/api/selected-org-secrets.json +0 -0
  394. {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_data/api/variables.json +0 -0
  395. {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_data/api/workflows.json +0 -0
  396. {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_description_docs.py +0 -0
  397. {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_enterprise_capabilities.py +0 -0
  398. {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_enterprise_organization.py +0 -0
  399. {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_enterprise_resources.py +0 -0
  400. {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_environment_model.py +0 -0
  401. {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_environment_resources.py +0 -0
  402. {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_environment_reviewer_lookup.py +0 -0
  403. {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_error_resilience.py +0 -0
  404. {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_github_app_retry.py +0 -0
  405. {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_github_rest_client.py +0 -0
  406. {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_github_retry.py +0 -0
  407. {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_helpers.py +0 -0
  408. {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_lookup.py +0 -0
  409. {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_org_scim_resources.py +0 -0
  410. {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_org_secret_models.py +0 -0
  411. {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_runner_ids.py +0 -0
  412. {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_runner_models.py +0 -0
  413. {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_runner_resources.py +0 -0
  414. {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_saml_helpers.py +0 -0
  415. {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_saml_models.py +0 -0
  416. {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_scim_models.py +0 -0
  417. {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_source_endpoints.py +0 -0
  418. {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_source_org_canonicalization.py +0 -0
  419. {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_team_external_groups.py +0 -0
  420. {openhound_github-0.8.0 → openhound_github-0.9.0}/tests/test_variable_models.py +0 -0
  421. {openhound_github-0.8.0 → openhound_github-0.9.0}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: openhound-github
3
- Version: 0.8.0
3
+ Version: 0.9.0
4
4
  Summary: Github collector for OpenHound
5
5
  Author-email: "jdreijer@specterops.io" <jdreijer@specterops.io>, Jared Atkinson <jatkinson@specterops.io>
6
6
  License-File: LICENSE.md
@@ -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 workflow (or job) explicitly declares `id-token: write` in its `permissions:` block. The `id-token` permission defaults to `none` and is never implicitly granted — even when the workflow has no `permissions:` block at all. The `permissions` property on the GH_WorkflowJob node can be inspected to verify this.
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]` | Effective job permissions. |
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 &mdash; Hygiene & Governance
84
88
 
85
89
  | # | File | Name | Description |
86
90
  |---|------|------|-------------|
87
- | 42 | `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. |
88
- | 43 | `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. |
89
- | 44 | `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. |
90
- | 45 | `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. |
91
- | 46 | `org-owners.json` | Organization Owners | Returns all users who hold the organization owners role. |
92
- | 47 | `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). |
93
- | 48 | `global-repo-perms.json` | Global Repo Permissions | Returns all users who hold a global repository permission role (i.e., roles that are not default). |
94
- | 49 | `hybrid-identities.json` | External Identities | Returns all external identities (e.g., Azure or Okta users) that are associated with GitHub users. |
95
- | 50 | `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. |
96
- | 51 | `saml-configuration.json` | SAML Configuration Mapping | Finds SAML Identity Providers, their external identities, and mapped users. |
97
- | 52 | `team-membership-admin.json` | Team Membership Admins | Returns all users who hold the maintainer role over a team, including team nesting. |
98
- | 53 | `team-structure.json` | Team Structure | Returns the structure of teams within organizations, including team roles and their members. |
99
- | 54 | `repository-workflows.json` | Repository Workflows | Returns all repository workflows. |
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
+ }
@@ -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,
@@ -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 parse_runs_on_selector
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: Effective job 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("permissions", mode="before")
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
- if value is None:
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,
@@ -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, repo: Repository, workflow: dict[str, Any]
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
- yield _workflow_file_contents(client, repo, workflow)
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: