RepoAuditor 0.2.26__tar.gz → 0.2.27__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 (135) hide show
  1. {repoauditor-0.2.26 → repoauditor-0.2.27}/PKG-INFO +1 -1
  2. {repoauditor-0.2.26 → repoauditor-0.2.27}/pyproject.toml +1 -0
  3. repoauditor-0.2.27/src/RepoAuditor/Plugins/GitHubRuleset.py +20 -0
  4. repoauditor-0.2.27/src/RepoAuditor/Plugins/GitHubRulesets/Module.py +49 -0
  5. repoauditor-0.2.27/src/RepoAuditor/Plugins/GitHubRulesets/Requirements/RequirePullRequests.py +47 -0
  6. repoauditor-0.2.27/src/RepoAuditor/Plugins/GitHubRulesets/Requirements/RequireSignedCommits.py +47 -0
  7. repoauditor-0.2.27/src/RepoAuditor/Plugins/GitHubRulesets/Requirements/RequireStatusChecks.py +47 -0
  8. repoauditor-0.2.27/src/RepoAuditor/Plugins/GitHubRulesets/RulesetQuery.py +53 -0
  9. repoauditor-0.2.27/src/RepoAuditor/Plugins/__init__.py +0 -0
  10. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/__init__.py +1 -1
  11. repoauditor-0.2.27/src/RepoAuditor/py.typed +0 -0
  12. {repoauditor-0.2.26 → repoauditor-0.2.27}/tests/CommandLineProcessor_UnitTest.py +19 -0
  13. repoauditor-0.2.27/tests/Plugins/GitHubRuleset_UnitTest.py +213 -0
  14. {repoauditor-0.2.26 → repoauditor-0.2.27}/.copier-answers.yml +0 -0
  15. {repoauditor-0.2.26 → repoauditor-0.2.27}/.github/CODEOWNERS +0 -0
  16. {repoauditor-0.2.26 → repoauditor-0.2.27}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  17. {repoauditor-0.2.26 → repoauditor-0.2.27}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  18. {repoauditor-0.2.26 → repoauditor-0.2.27}/.github/ISSUE_TEMPLATE/custom.md +0 -0
  19. {repoauditor-0.2.26 → repoauditor-0.2.27}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  20. {repoauditor-0.2.26 → repoauditor-0.2.27}/.github/actions/release_impl/action.yml +0 -0
  21. {repoauditor-0.2.26 → repoauditor-0.2.27}/.github/pull_request_template.md +0 -0
  22. {repoauditor-0.2.26 → repoauditor-0.2.27}/.github/release_sources.yaml +0 -0
  23. {repoauditor-0.2.26 → repoauditor-0.2.27}/.github/workflows/CICD.yml +0 -0
  24. {repoauditor-0.2.26 → repoauditor-0.2.27}/.github/workflows/CICD_impl.yml +0 -0
  25. {repoauditor-0.2.26 → repoauditor-0.2.27}/.github/workflows/EndToEnd.yml +0 -0
  26. {repoauditor-0.2.26 → repoauditor-0.2.27}/.github/workflows/codeql.yml +0 -0
  27. {repoauditor-0.2.26 → repoauditor-0.2.27}/.gitignore +0 -0
  28. {repoauditor-0.2.26 → repoauditor-0.2.27}/.pre-commit-config.yaml +0 -0
  29. {repoauditor-0.2.26 → repoauditor-0.2.27}/.python-version +0 -0
  30. {repoauditor-0.2.26 → repoauditor-0.2.27}/CODE_OF_CONDUCT.md +0 -0
  31. {repoauditor-0.2.26 → repoauditor-0.2.27}/CONTRIBUTING.md +0 -0
  32. {repoauditor-0.2.26 → repoauditor-0.2.27}/DEVELOPMENT.md +0 -0
  33. {repoauditor-0.2.26 → repoauditor-0.2.27}/GOVERNANCE.md +0 -0
  34. {repoauditor-0.2.26 → repoauditor-0.2.27}/LICENSE +0 -0
  35. {repoauditor-0.2.26 → repoauditor-0.2.27}/MAINTAINERS.md +0 -0
  36. {repoauditor-0.2.26 → repoauditor-0.2.27}/README.md +0 -0
  37. {repoauditor-0.2.26 → repoauditor-0.2.27}/SECURITY.md +0 -0
  38. {repoauditor-0.2.26 → repoauditor-0.2.27}/minisign_key.pub +0 -0
  39. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/AutoGitSemVer.yaml +0 -0
  40. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/CommandLineProcessor.py +0 -0
  41. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Display.py +0 -0
  42. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/EntryPoint.py +0 -0
  43. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/ExecuteModules.py +0 -0
  44. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Impl/ParallelSequentialProcessor.py +0 -0
  45. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Impl/__init__.py +0 -0
  46. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Module.py +0 -0
  47. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugin.py +0 -0
  48. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHub/ClassicBranchProtectionQuery.py +0 -0
  49. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHub/ClassicBranchProtectionRequirements/AllowDeletions.py +0 -0
  50. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHub/ClassicBranchProtectionRequirements/AllowForcePushes.py +0 -0
  51. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHub/ClassicBranchProtectionRequirements/DismissStalePullRequestApprovals.py +0 -0
  52. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHub/ClassicBranchProtectionRequirements/DoNotAllowBypassSettings.py +0 -0
  53. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHub/ClassicBranchProtectionRequirements/EnsureStatusChecks.py +0 -0
  54. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHub/ClassicBranchProtectionRequirements/Impl/ClassicEnableRequirementImpl.py +0 -0
  55. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHub/ClassicBranchProtectionRequirements/Impl/ClassicValueRequirementImpl.py +0 -0
  56. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHub/ClassicBranchProtectionRequirements/Impl/__init__.py +0 -0
  57. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHub/ClassicBranchProtectionRequirements/RequireApprovalMostRecentPush.py +0 -0
  58. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHub/ClassicBranchProtectionRequirements/RequireApprovals.py +0 -0
  59. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHub/ClassicBranchProtectionRequirements/RequireCodeOwnerReview.py +0 -0
  60. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHub/ClassicBranchProtectionRequirements/RequireConversationResolution.py +0 -0
  61. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHub/ClassicBranchProtectionRequirements/RequireLinearHistory.py +0 -0
  62. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHub/ClassicBranchProtectionRequirements/RequirePullRequests.py +0 -0
  63. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHub/ClassicBranchProtectionRequirements/RequireSignedCommits.py +0 -0
  64. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHub/ClassicBranchProtectionRequirements/RequireStatusChecksToPass.py +0 -0
  65. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHub/ClassicBranchProtectionRequirements/RequireUpToDateBranches.py +0 -0
  66. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHub/ClassicBranchProtectionRequirements/__init__.py +0 -0
  67. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHub/DefaultBranchQuery.py +0 -0
  68. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHub/DefaultBranchQueryRequirements/Protected.py +0 -0
  69. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHub/DefaultBranchQueryRequirements/__init__.py +0 -0
  70. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHub/Impl/Common.py +0 -0
  71. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHub/Impl/EnableRequirementImpl.py +0 -0
  72. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHub/Impl/ValueRequirementImpl.py +0 -0
  73. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHub/Impl/__init__.py +0 -0
  74. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHub/Module.py +0 -0
  75. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHub/StandardQuery.py +0 -0
  76. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/AutoMerge.py +0 -0
  77. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/DefaultBranch.py +0 -0
  78. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/DeleteHeadBranches.py +0 -0
  79. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/DependabotSecurityUpdates.py +0 -0
  80. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/Description.py +0 -0
  81. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/Impl/StandardEnableRequirementImpl.py +0 -0
  82. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/Impl/StandardValueRequirementImpl.py +0 -0
  83. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/Impl/__init__.py +0 -0
  84. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/License.py +0 -0
  85. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/MergeCommit.py +0 -0
  86. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/MergeCommitMessage.py +0 -0
  87. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/Private.py +0 -0
  88. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/RebaseMergeCommit.py +0 -0
  89. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/SecretScanning.py +0 -0
  90. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/SecretScanningPushProtection.py +0 -0
  91. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/SquashCommitMerge.py +0 -0
  92. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/SquashMergeCommitMessage.py +0 -0
  93. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/SuggestUpdatingPullRequestBranches.py +0 -0
  94. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/SupportDiscussions.py +0 -0
  95. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/SupportIssues.py +0 -0
  96. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/SupportProjects.py +0 -0
  97. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/SupportWikis.py +0 -0
  98. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/TemplateRepository.py +0 -0
  99. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/WebCommitSignoff.py +0 -0
  100. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/__init__.py +0 -0
  101. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHub/__init__.py +0 -0
  102. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHubBase/Module.py +0 -0
  103. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHubBase/__init__.py +0 -0
  104. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHubCustomization/CustomizationQuery.py +0 -0
  105. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHubCustomization/Impl/ExistsRequirementImpl.py +0 -0
  106. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHubCustomization/Impl/__init__.py +0 -0
  107. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHubCustomization/Module.py +0 -0
  108. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHubCustomization/Requirements/CodeOwners.py +0 -0
  109. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHubCustomization/Requirements/Contributing.py +0 -0
  110. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHubCustomization/Requirements/IssueTemplates.py +0 -0
  111. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHubCustomization/Requirements/PullRequestTemplates.py +0 -0
  112. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHubCustomization/Requirements/SecurityPolicy.py +0 -0
  113. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHubCustomization/Requirements/__init__.py +0 -0
  114. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHubCustomization/__init__.py +0 -0
  115. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHubCustomizationPlugin.py +0 -0
  116. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Plugins/GitHubPlugin.py +0 -0
  117. {repoauditor-0.2.26/src/RepoAuditor/Plugins → repoauditor-0.2.27/src/RepoAuditor/Plugins/GitHubRulesets/Requirements}/__init__.py +0 -0
  118. /repoauditor-0.2.26/src/RepoAuditor/py.typed → /repoauditor-0.2.27/src/RepoAuditor/Plugins/GitHubRulesets/__init__.py +0 -0
  119. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Query.py +0 -0
  120. {repoauditor-0.2.26 → repoauditor-0.2.27}/src/RepoAuditor/Requirement.py +0 -0
  121. {repoauditor-0.2.26 → repoauditor-0.2.27}/tests/EntryPoint_UnitTest.py +0 -0
  122. {repoauditor-0.2.26 → repoauditor-0.2.27}/tests/ExecuteModules_UnitTest.py +0 -0
  123. {repoauditor-0.2.26 → repoauditor-0.2.27}/tests/Module_UnitTest.py +0 -0
  124. {repoauditor-0.2.26 → repoauditor-0.2.27}/tests/Plugin_UnitTest.py +0 -0
  125. {repoauditor-0.2.26 → repoauditor-0.2.27}/tests/Plugins/GitHubCustomization_EndToEndTest.py +0 -0
  126. {repoauditor-0.2.26 → repoauditor-0.2.27}/tests/Plugins/GitHubCustomization_UnitTest.py +0 -0
  127. {repoauditor-0.2.26 → repoauditor-0.2.27}/tests/Plugins/GitHubModule_UnitTest.py +0 -0
  128. {repoauditor-0.2.26 → repoauditor-0.2.27}/tests/Plugins/GitHub_EndToEndTest.py +0 -0
  129. {repoauditor-0.2.26 → repoauditor-0.2.27}/tests/Plugins/__snapshots__/GitHubCustomization_EndToEndTest.ambr +0 -0
  130. {repoauditor-0.2.26 → repoauditor-0.2.27}/tests/Plugins/__snapshots__/GitHub_EndToEndTest.ambr +0 -0
  131. {repoauditor-0.2.26 → repoauditor-0.2.27}/tests/Plugins/utilities.py +0 -0
  132. {repoauditor-0.2.26 → repoauditor-0.2.27}/tests/Query_UnitTest.py +0 -0
  133. {repoauditor-0.2.26 → repoauditor-0.2.27}/tests/Requirement_UnitTest.py +0 -0
  134. {repoauditor-0.2.26 → repoauditor-0.2.27}/tests/__snapshots__/ExecuteModules_UnitTest.ambr +0 -0
  135. {repoauditor-0.2.26 → repoauditor-0.2.27}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: RepoAuditor
3
- Version: 0.2.26
3
+ Version: 0.2.27
4
4
  Summary: Add your description here
5
5
  Project-URL: Homepage, https://github.com/gt-sse-center/RepoAuditor
6
6
  Project-URL: Documentation, https://github.com/gt-sse-center/RepoAuditor
@@ -39,6 +39,7 @@ repo_auditor = "RepoAuditor:EntryPoint.app"
39
39
  [project.entry-points.RepoAuditor]
40
40
  GitHubPlugin = "RepoAuditor.Plugins.GitHubPlugin"
41
41
  GitHubCustomizationPlugin = "RepoAuditor.Plugins.GitHubCustomizationPlugin"
42
+ GitHubRulesetPlugin="RepoAuditor.Plugins.GitHubRuleset"
42
43
 
43
44
  [build-system]
44
45
  requires = ["hatchling"]
@@ -0,0 +1,20 @@
1
+ # -------------------------------------------------------------------------------
2
+ # |
3
+ # | Copyright (c) 2024 Scientific Software Engineering Center at Georgia Tech
4
+ # | Distributed under the MIT License.
5
+ # |
6
+ # -------------------------------------------------------------------------------
7
+ """Contains Plugin functionality."""
8
+
9
+ import pluggy
10
+
11
+ from RepoAuditor import APP_NAME
12
+ from RepoAuditor.Module import Module
13
+
14
+ from RepoAuditor.Plugins.GitHubRulesets.Module import GitHubRulesetModule
15
+
16
+
17
+ @pluggy.HookimplMarker(APP_NAME)
18
+ def GetModule() -> Module:
19
+ """Return GitHubRulesetModule Module."""
20
+ return GitHubRulesetModule()
@@ -0,0 +1,49 @@
1
+ # -------------------------------------------------------------------------------
2
+ # |
3
+ # | Copyright (c) 2024 Scientific Software Engineering Center at Georgia Tech
4
+ # | Distributed under the MIT License.
5
+ # |
6
+ # -------------------------------------------------------------------------------
7
+ """Contains the GitHubRulesetModule object."""
8
+
9
+ import typer
10
+
11
+ from dbrownell_Common.TyperEx import TypeDefinitionItemType
12
+ from dbrownell_Common.Types import override
13
+
14
+ from RepoAuditor.Module import ExecutionStyle
15
+ from RepoAuditor.Plugins.GitHubBase.Module import GitHubBaseModule
16
+ from RepoAuditor.Plugins.GitHubRulesets.RulesetQuery import RulesetQuery
17
+
18
+
19
+ class GitHubRulesetModule(GitHubBaseModule):
20
+ """Module that validates GitHub repository rulesets."""
21
+
22
+ def __init__(self) -> None:
23
+ super().__init__(
24
+ "GitHubRuleset",
25
+ "Validates GitHub repository rulesets.",
26
+ ExecutionStyle.Parallel,
27
+ [RulesetQuery()],
28
+ requires_explicit_include=True,
29
+ )
30
+
31
+ @override
32
+ def GetDynamicArgDefinitions(self) -> dict[str, TypeDefinitionItemType]:
33
+ """Get the definitions for the arguments to this requirement."""
34
+ return {
35
+ "url": (
36
+ str,
37
+ typer.Option(
38
+ ...,
39
+ help="[REQUIRED] GitHub repository URL (e.g., https://github.com/owner/repo).",
40
+ ),
41
+ ),
42
+ "branch": (
43
+ str,
44
+ typer.Option(
45
+ None,
46
+ help="Branch to evaluate. The default branch will be used if not specified.",
47
+ ),
48
+ ),
49
+ }
@@ -0,0 +1,47 @@
1
+ # -------------------------------------------------------------------------------
2
+ # |
3
+ # | Copyright (c) 2024 Scientific Software Engineering Center at Georgia Tech
4
+ # | Distributed under the MIT License.
5
+ # |
6
+ # -------------------------------------------------------------------------------
7
+ """Contains the RequirePullRequests object."""
8
+
9
+ from typing import override, Any
10
+ from RepoAuditor.Requirement import EvaluateResult, ExecutionStyle, Requirement
11
+
12
+
13
+ class RequirePullRequests(Requirement):
14
+ """Implement the Pull Requests required ruleset for the branch."""
15
+
16
+ def __init__(self) -> None:
17
+ super().__init__(
18
+ name="RequirePullRequests",
19
+ description="Require pull requests before merging to default branch",
20
+ style=ExecutionStyle.Parallel,
21
+ resolution_template="Enable pull request requirements in repository rulesets",
22
+ rationale_template="Pull request reviews help maintain code quality and collaboration",
23
+ )
24
+
25
+ @override
26
+ def _EvaluateImpl(
27
+ self,
28
+ query_data: dict[str, Any],
29
+ requirement_args: dict[str, Any],
30
+ ) -> Requirement.EvaluateImplResult:
31
+ rulesets = query_data.get("rulesets", [])
32
+
33
+ for ruleset in rulesets:
34
+ if (
35
+ ruleset.get("enforcement", "") == "active"
36
+ and ruleset.get("target", "") == "branch"
37
+ and ruleset.get("parameters", {}).get("pull_request", {}).get("required", False)
38
+ ):
39
+ return self.EvaluateImplResult(
40
+ EvaluateResult.Success, f"Ruleset '{ruleset['name']}' enforces pull requests"
41
+ )
42
+
43
+ return self.EvaluateImplResult(
44
+ EvaluateResult.Error,
45
+ "No active branch ruleset requiring pull requests found",
46
+ provide_resolution=True,
47
+ )
@@ -0,0 +1,47 @@
1
+ # -------------------------------------------------------------------------------
2
+ # |
3
+ # | Copyright (c) 2024 Scientific Software Engineering Center at Georgia Tech
4
+ # | Distributed under the MIT License.
5
+ # |
6
+ # -------------------------------------------------------------------------------
7
+ """Contains the RequireSignedCommits object."""
8
+
9
+ from typing import override, Any
10
+ from RepoAuditor.Requirement import EvaluateResult, ExecutionStyle, Requirement
11
+
12
+
13
+ class RequireSignedCommits(Requirement):
14
+ """Implement the Signed Commits required ruleset for a branch."""
15
+
16
+ def __init__(self) -> None:
17
+ super().__init__(
18
+ name="RequireSignedCommits",
19
+ description="Require signed commits",
20
+ style=ExecutionStyle.Parallel,
21
+ resolution_template="Enable commit signing requirement in repository rulesets",
22
+ rationale_template="Signed commits ensure commit authenticity",
23
+ )
24
+
25
+ @override
26
+ def _EvaluateImpl(
27
+ self,
28
+ query_data: dict[str, Any],
29
+ requirement_args: dict[str, Any],
30
+ ) -> Requirement.EvaluateImplResult:
31
+ rulesets = query_data.get("rulesets", [])
32
+
33
+ for ruleset in rulesets:
34
+ if (
35
+ ruleset.get("enforcement", "") == "active"
36
+ and ruleset.get("target", "") == "branch"
37
+ and ruleset.get("parameters", {}).get("commit_signatures", False)
38
+ ):
39
+ return self.EvaluateImplResult(
40
+ EvaluateResult.Success, f"Ruleset '{ruleset['name']}' enforces signed commits"
41
+ )
42
+
43
+ return self.EvaluateImplResult(
44
+ EvaluateResult.Error,
45
+ "No active branch ruleset requiring signed commits found",
46
+ provide_resolution=True,
47
+ )
@@ -0,0 +1,47 @@
1
+ # -------------------------------------------------------------------------------
2
+ # |
3
+ # | Copyright (c) 2024 Scientific Software Engineering Center at Georgia Tech
4
+ # | Distributed under the MIT License.
5
+ # |
6
+ # -------------------------------------------------------------------------------
7
+ """Contains the RequireStatusChecks object."""
8
+
9
+ from typing import override, Any
10
+ from RepoAuditor.Requirement import EvaluateResult, ExecutionStyle, Requirement
11
+
12
+
13
+ class RequireStatusChecks(Requirement):
14
+ """Implement the Status Check ruleset for a branch."""
15
+
16
+ def __init__(self) -> None:
17
+ super().__init__(
18
+ name="RequireStatusChecks",
19
+ description="Require status checks to pass before merging",
20
+ style=ExecutionStyle.Parallel,
21
+ resolution_template="Configure required status checks in repository rulesets",
22
+ rationale_template="Status checks ensure code quality and compatibility",
23
+ )
24
+
25
+ @override
26
+ def _EvaluateImpl(
27
+ self,
28
+ query_data: dict[str, Any],
29
+ requirement_args: dict[str, Any],
30
+ ) -> Requirement.EvaluateImplResult:
31
+ rulesets = query_data.get("rulesets", [])
32
+
33
+ for ruleset in rulesets:
34
+ if (
35
+ ruleset.get("enforcement", "") == "active"
36
+ and ruleset.get("target", "") == "branch"
37
+ and len(ruleset.get("parameters", {}).get("required_status_checks", [])) > 0
38
+ ):
39
+ return self.EvaluateImplResult(
40
+ EvaluateResult.Success, f"Ruleset '{ruleset['name']}' enforces status checks"
41
+ )
42
+
43
+ return self.EvaluateImplResult(
44
+ EvaluateResult.Error,
45
+ "No active branch ruleset requiring status checks found",
46
+ provide_resolution=True,
47
+ )
@@ -0,0 +1,53 @@
1
+ # -------------------------------------------------------------------------------
2
+ # |
3
+ # | Copyright (c) 2024 Scientific Software Engineering Center at Georgia Tech
4
+ # | Distributed under the MIT License.
5
+ # |
6
+ # -------------------------------------------------------------------------------
7
+ """Contains the RulesetQuery object."""
8
+
9
+ from typing import Any, Optional
10
+
11
+ from dbrownell_Common.Types import override
12
+ from RepoAuditor.Impl.ParallelSequentialProcessor import ExecutionStyle
13
+ from RepoAuditor.Query import Query
14
+ from RepoAuditor.Plugins.GitHubRulesets.Requirements.RequirePullRequests import RequirePullRequests
15
+ from RepoAuditor.Plugins.GitHubRulesets.Requirements.RequireSignedCommits import RequireSignedCommits
16
+ from RepoAuditor.Plugins.GitHubRulesets.Requirements.RequireStatusChecks import RequireStatusChecks
17
+
18
+
19
+ class RulesetQuery(Query):
20
+ """Query to validate GitHub repository rulesets."""
21
+
22
+ def __init__(self) -> None:
23
+ super().__init__(
24
+ "RulesetQuery",
25
+ ExecutionStyle.Parallel,
26
+ [
27
+ RequireStatusChecks(),
28
+ RequirePullRequests(),
29
+ RequireSignedCommits(),
30
+ ],
31
+ )
32
+
33
+ @override
34
+ def GetData(
35
+ self,
36
+ module_data: dict[str, Any],
37
+ ) -> Optional[dict[str, Any]]:
38
+ """Retrieve data required for validating GitHub rulesets.
39
+
40
+ Args:
41
+ module_data (dict): Dictionary containing initial data from the module.
42
+
43
+ Returns:
44
+ Optional[dict]: A dictionary containing ruleset-related
45
+ data, or None if an error occurs.
46
+
47
+ """
48
+ # Fetch ruleset data from the GitHub API
49
+ ruleset_data = module_data["session"].get("rulesets")
50
+
51
+ # Add ruleset data to module_data
52
+ module_data["ruleset_data"] = ruleset_data
53
+ return module_data
File without changes
@@ -3,4 +3,4 @@ APP_NAME = "RepoAuditor"
3
3
  # Note that this value will be overwritten by calls to `python ../../Build.py update_version` based
4
4
  # on changes observed in the git repository. The default value below will be used until the value
5
5
  # here is explicitly updated by the Continuous Integration system.
6
- __version__ = "0.2.26"
6
+ __version__ = "0.2.27"
File without changes
@@ -446,3 +446,22 @@ def test_InvalidArgName():
446
446
  set(),
447
447
  set(),
448
448
  )
449
+
450
+
451
+ # ----------------------------------------------------------------------
452
+ def test_InvalidArgs():
453
+ """Check if an invalid module is specified as an argument."""
454
+ with pytest.raises(
455
+ Exception,
456
+ match=re.escape("'InvalidModule' is not a recognized module name."),
457
+ ):
458
+ CommandLineProcessor.Create(
459
+ # Specify an unregistered module
460
+ get_dynamic_args_func=lambda dynamic_arg_definitions: {"InvalidModule-arg1": "value"},
461
+ # ValidModule is the registered module.
462
+ modules=[MyModule(name="ValidModule")],
463
+ includes=["InvalidModule"],
464
+ excludes=[],
465
+ warnings_as_error_module_names=set(),
466
+ ignore_warnings_module_names=set(),
467
+ )
@@ -0,0 +1,213 @@
1
+ # -------------------------------------------------------------------------------
2
+ # |
3
+ # | Copyright (c) 2024 Scientific Software Engineering Center at Georgia Tech
4
+ # | Distributed under the MIT License.
5
+ # |
6
+ # -------------------------------------------------------------------------------
7
+ """Unit tests for the GitHub Rulesets Plugin"""
8
+
9
+ from RepoAuditor.Requirement import EvaluateResult
10
+ from RepoAuditor.Plugins.GitHubRulesets.Requirements.RequirePullRequests import RequirePullRequests
11
+ from RepoAuditor.Plugins.GitHubRulesets.Requirements.RequireStatusChecks import RequireStatusChecks
12
+ from RepoAuditor.Plugins.GitHubRulesets.Requirements.RequireSignedCommits import (
13
+ RequireSignedCommits,
14
+ )
15
+
16
+
17
+ def create_ruleset(name, target, enforcement, parameters):
18
+ """Helper function to create ruleset structure"""
19
+ return {"name": name, "target": target, "enforcement": enforcement, "parameters": parameters}
20
+
21
+
22
+ # ----------------------------------------------------------------------
23
+ class TestRequirePullRequests:
24
+ """Unit tests for the RequirePullRequests requirement."""
25
+
26
+ def test_Enabled(self):
27
+ requirement = RequirePullRequests() # type: ignore
28
+ context = {
29
+ "rulesets": [
30
+ create_ruleset(
31
+ name="PR Rules",
32
+ target="branch",
33
+ enforcement="active",
34
+ parameters={"pull_request": {"required": True, "require_code_owner_review": True}},
35
+ )
36
+ ]
37
+ }
38
+ result = requirement.Evaluate(context, {})
39
+ assert result.result == EvaluateResult.Success
40
+ assert "enforces pull requests" in result.context
41
+
42
+ def test_Disabled(self):
43
+ requirement = RequirePullRequests() # type: ignore
44
+ context = {
45
+ "rulesets": [
46
+ create_ruleset(
47
+ name="Inactive PR Rules",
48
+ target="branch",
49
+ enforcement="disabled", # Wrong enforcement
50
+ parameters={"pull_request": {"required": True}},
51
+ )
52
+ ]
53
+ }
54
+ result = requirement.Evaluate(context, {})
55
+ assert result.result == EvaluateResult.Error
56
+
57
+ def test_WrongTarget(self):
58
+ requirement = RequirePullRequests() # type: ignore
59
+ context = {
60
+ "rulesets": [
61
+ create_ruleset(
62
+ name="Wrong Target Rules",
63
+ target="tag", # Wrong target
64
+ enforcement="active",
65
+ parameters={"pull_request": {"required": True}},
66
+ )
67
+ ]
68
+ }
69
+ result = requirement.Evaluate(context, {})
70
+ assert result.result == EvaluateResult.Error
71
+
72
+ def test_MissingParameter(self):
73
+ requirement = RequirePullRequests() # type: ignore
74
+ context = {
75
+ "rulesets": [
76
+ create_ruleset(
77
+ name="Partial Rules",
78
+ target="branch",
79
+ enforcement="active",
80
+ parameters={"other_rule": {}}, # Missing pull_request
81
+ )
82
+ ]
83
+ }
84
+ result = requirement.Evaluate(context, {})
85
+ assert result.result == EvaluateResult.Error
86
+
87
+ def test_NoRulesets(self):
88
+ requirement = RequirePullRequests() # type: ignore
89
+ context = {"rulesets": []}
90
+ result = requirement.Evaluate(context, {})
91
+ assert result.result == EvaluateResult.Error
92
+ assert "No active branch ruleset requiring pull requests found" in result.context
93
+
94
+
95
+ # ----------------------------------------------------------------------
96
+ class TestRequireSignedCommits:
97
+ """Unit tests for the RequireSignedCommits requirement."""
98
+
99
+ def test_Enabled(self):
100
+ requirement = RequireSignedCommits() # type: ignore
101
+ context = {
102
+ "rulesets": [
103
+ create_ruleset(
104
+ name="Signing Rules",
105
+ target="branch",
106
+ enforcement="active",
107
+ parameters={"commit_signatures": True},
108
+ )
109
+ ]
110
+ }
111
+ result = requirement.Evaluate(context, {})
112
+ assert result.result == EvaluateResult.Success
113
+ assert "enforces signed commits" in result.context
114
+
115
+ def test_Disabled(self):
116
+ requirement = RequireSignedCommits() # type: ignore
117
+ context = {
118
+ "rulesets": [
119
+ create_ruleset(
120
+ name="Inactive Signing",
121
+ target="branch",
122
+ enforcement="evaluate", # Wrong enforcement
123
+ parameters={"commit_signatures": True},
124
+ )
125
+ ]
126
+ }
127
+ result = requirement.Evaluate(context, {})
128
+ assert result.result == EvaluateResult.Error
129
+
130
+ def test_PartialConfig(self):
131
+ requirement = RequireSignedCommits() # type: ignore
132
+ context = {
133
+ "rulesets": [
134
+ create_ruleset(
135
+ name="Partial Config",
136
+ target="branch",
137
+ enforcement="active",
138
+ parameters={"commit_signatures": False}, # Explicitly disabled
139
+ )
140
+ ]
141
+ }
142
+ result = requirement.Evaluate(context, {})
143
+ assert result.result == EvaluateResult.Error
144
+
145
+ def test_NoRulesets(self):
146
+ requirement = RequireSignedCommits() # type: ignore
147
+ context = {"rulesets": []}
148
+ result = requirement.Evaluate(context, {})
149
+ assert result.result == EvaluateResult.Error
150
+ assert "No active branch ruleset requiring signed commits found" in result.context
151
+
152
+
153
+ # ----------------------------------------------------------------------
154
+ class TestRequireStatusChecks:
155
+ """Unit tests for the RequireStatusChecks requirement."""
156
+
157
+ def test_Enabled(self):
158
+ requirement = RequireStatusChecks() # type: ignore
159
+ context = {
160
+ "rulesets": [
161
+ create_ruleset(
162
+ name="CI Checks",
163
+ target="branch",
164
+ enforcement="active",
165
+ parameters={
166
+ "required_status_checks": [
167
+ {"context": "ci-test"},
168
+ {"context": "security-scan"},
169
+ ]
170
+ },
171
+ )
172
+ ]
173
+ }
174
+ result = requirement.Evaluate(context, {})
175
+ assert result.result == EvaluateResult.Success
176
+ assert "enforces status checks" in result.context
177
+
178
+ def test_EmptyChecks(self):
179
+ requirement = RequireStatusChecks() # type: ignore
180
+ context = {
181
+ "rulesets": [
182
+ create_ruleset(
183
+ name="Empty Checks",
184
+ target="branch",
185
+ enforcement="active",
186
+ parameters={"required_status_checks": []}, # Empty list
187
+ )
188
+ ]
189
+ }
190
+ result = requirement.Evaluate(context, {})
191
+ assert result.result == EvaluateResult.Error
192
+
193
+ def test_InactiveRuleset(self):
194
+ requirement = RequireStatusChecks() # type: ignore
195
+ context = {
196
+ "rulesets": [
197
+ create_ruleset(
198
+ name="Inactive Checks",
199
+ target="branch",
200
+ enforcement="disabled", # Inactive
201
+ parameters={"required_status_checks": [{"context": "ci-test"}]},
202
+ )
203
+ ]
204
+ }
205
+ result = requirement.Evaluate(context, {})
206
+ assert result.result == EvaluateResult.Error
207
+
208
+ def test_NoRulesets(self):
209
+ requirement = RequireStatusChecks() # type: ignore
210
+ context = {"rulesets": []}
211
+ result = requirement.Evaluate(context, {})
212
+ assert result.result == EvaluateResult.Error
213
+ assert "No active branch ruleset requiring status checks found" in result.context
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes