gitlabcis 1.3.2__py3-none-any.whl

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 (218) hide show
  1. gitlabcis/__init__.py +12 -0
  2. gitlabcis/__main__.py +7 -0
  3. gitlabcis/benchmarks/__init__.py +8 -0
  4. gitlabcis/benchmarks/artifacts_4/__init__.py +4 -0
  5. gitlabcis/benchmarks/artifacts_4/access_to_artifacts_4_2.py +139 -0
  6. gitlabcis/benchmarks/artifacts_4/origin_traceability_4_4.py +11 -0
  7. gitlabcis/benchmarks/artifacts_4/package_registries_4_3.py +105 -0
  8. gitlabcis/benchmarks/artifacts_4/verification_4_1.py +83 -0
  9. gitlabcis/benchmarks/build_pipelines_2/__init__.py +4 -0
  10. gitlabcis/benchmarks/build_pipelines_2/build_environment_2_1.py +268 -0
  11. gitlabcis/benchmarks/build_pipelines_2/build_worker_2_2.py +129 -0
  12. gitlabcis/benchmarks/build_pipelines_2/pipeline_instructions_2_3.py +444 -0
  13. gitlabcis/benchmarks/build_pipelines_2/pipeline_integrity_2_4.py +146 -0
  14. gitlabcis/benchmarks/dependencies_3/__init__.py +2 -0
  15. gitlabcis/benchmarks/dependencies_3/third_party_packages_3_1.py +171 -0
  16. gitlabcis/benchmarks/dependencies_3/validate_packages_3_2.py +182 -0
  17. gitlabcis/benchmarks/deployment_5/__init__.py +2 -0
  18. gitlabcis/benchmarks/deployment_5/deployment_configuration_5_1.py +165 -0
  19. gitlabcis/benchmarks/deployment_5/deployment_environment_5_2.py +66 -0
  20. gitlabcis/benchmarks/source_code_1/__init__.py +6 -0
  21. gitlabcis/benchmarks/source_code_1/code_changes_1_1.py +665 -0
  22. gitlabcis/benchmarks/source_code_1/code_risks_1_5.py +506 -0
  23. gitlabcis/benchmarks/source_code_1/contribution_access_1_3.py +334 -0
  24. gitlabcis/benchmarks/source_code_1/repository_management_1_2.py +168 -0
  25. gitlabcis/benchmarks/source_code_1/third_party_1_4.py +139 -0
  26. gitlabcis/cli/__init__.py +0 -0
  27. gitlabcis/cli/log.py +30 -0
  28. gitlabcis/cli/main.py +541 -0
  29. gitlabcis/cli/output.py +151 -0
  30. gitlabcis/recommendations/artifacts_4/access_to_artifacts_4_2/external_auth_server.yml +51 -0
  31. gitlabcis/recommendations/artifacts_4/access_to_artifacts_4_2/limit_artifact_uploaders.yml +57 -0
  32. gitlabcis/recommendations/artifacts_4/access_to_artifacts_4_2/limit_certifying_artifacts.yml +53 -0
  33. gitlabcis/recommendations/artifacts_4/access_to_artifacts_4_2/minimum_package_registry_admins.yml +54 -0
  34. gitlabcis/recommendations/artifacts_4/access_to_artifacts_4_2/readme.md +14 -0
  35. gitlabcis/recommendations/artifacts_4/access_to_artifacts_4_2/require_mfa_to_package_registry.yml +52 -0
  36. gitlabcis/recommendations/artifacts_4/access_to_artifacts_4_2/restrict_anonymous_access.yml +67 -0
  37. gitlabcis/recommendations/artifacts_4/origin_traceability_4_4/artifact_origin_info.yml +56 -0
  38. gitlabcis/recommendations/artifacts_4/origin_traceability_4_4/readme.md +7 -0
  39. gitlabcis/recommendations/artifacts_4/package_registries_4_3/all_artifact_versions_signed.yml +70 -0
  40. gitlabcis/recommendations/artifacts_4/package_registries_4_3/audit_package_registry_config.yml +46 -0
  41. gitlabcis/recommendations/artifacts_4/package_registries_4_3/readme.md +12 -0
  42. gitlabcis/recommendations/artifacts_4/package_registries_4_3/secure_repo_webhooks.yml +50 -0
  43. gitlabcis/recommendations/artifacts_4/package_registries_4_3/validate_signed_artifacts_on_upload.yml +72 -0
  44. gitlabcis/recommendations/artifacts_4/readme.md +12 -0
  45. gitlabcis/recommendations/artifacts_4/verification_4_1/encrypt_artifacts_before_distribution.yml +47 -0
  46. gitlabcis/recommendations/artifacts_4/verification_4_1/only_authorized_platforms_can_decrypt_artifacts.yml +59 -0
  47. gitlabcis/recommendations/artifacts_4/verification_4_1/readme.md +11 -0
  48. gitlabcis/recommendations/artifacts_4/verification_4_1/sign_artifacts_in_build_pipeline.yml +40 -0
  49. gitlabcis/recommendations/build_pipelines_2/build_environment_2_1/authenticate_build_access.yml +55 -0
  50. gitlabcis/recommendations/build_pipelines_2/build_environment_2_1/build_automation.yml +54 -0
  51. gitlabcis/recommendations/build_pipelines_2/build_environment_2_1/build_env_admins.yml +55 -0
  52. gitlabcis/recommendations/build_pipelines_2/build_environment_2_1/build_logging.yml +49 -0
  53. gitlabcis/recommendations/build_pipelines_2/build_environment_2_1/disable_build_tools_default_passwords.yml +54 -0
  54. gitlabcis/recommendations/build_pipelines_2/build_environment_2_1/immutable_pipeline_infrastructure.yml +60 -0
  55. gitlabcis/recommendations/build_pipelines_2/build_environment_2_1/limit_build_access.yml +64 -0
  56. gitlabcis/recommendations/build_pipelines_2/build_environment_2_1/limit_build_secrets_scope.yml +56 -0
  57. gitlabcis/recommendations/build_pipelines_2/build_environment_2_1/readme.md +19 -0
  58. gitlabcis/recommendations/build_pipelines_2/build_environment_2_1/secure_build_env_webhooks.yml +43 -0
  59. gitlabcis/recommendations/build_pipelines_2/build_environment_2_1/single_responsibility_pipeline.yml +58 -0
  60. gitlabcis/recommendations/build_pipelines_2/build_environment_2_1/vuln_scanning.yml +64 -0
  61. gitlabcis/recommendations/build_pipelines_2/build_worker_2_2/build_worker_vuln_scanning.yml +58 -0
  62. gitlabcis/recommendations/build_pipelines_2/build_worker_2_2/monitor_worker_resource_consumption.yml +59 -0
  63. gitlabcis/recommendations/build_pipelines_2/build_worker_2_2/pass_worker_envs_and_commands.yml +48 -0
  64. gitlabcis/recommendations/build_pipelines_2/build_worker_2_2/readme.md +16 -0
  65. gitlabcis/recommendations/build_pipelines_2/build_worker_2_2/restrict_worker_connectivity.yml +61 -0
  66. gitlabcis/recommendations/build_pipelines_2/build_worker_2_2/segregate_worker_duties.yml +78 -0
  67. gitlabcis/recommendations/build_pipelines_2/build_worker_2_2/single_use_workers.yml +47 -0
  68. gitlabcis/recommendations/build_pipelines_2/build_worker_2_2/store_worker_config.yml +62 -0
  69. gitlabcis/recommendations/build_pipelines_2/build_worker_2_2/worker_runtime_security.yml +37 -0
  70. gitlabcis/recommendations/build_pipelines_2/pipeline_instructions_2_3/build_stage_io.yml +49 -0
  71. gitlabcis/recommendations/build_pipelines_2/pipeline_instructions_2_3/build_steps_as_code.yml +42 -0
  72. gitlabcis/recommendations/build_pipelines_2/pipeline_instructions_2_3/limit_pipeline_triggers.yml +76 -0
  73. gitlabcis/recommendations/build_pipelines_2/pipeline_instructions_2_3/pipeline_misconfiguration_scanning.yml +48 -0
  74. gitlabcis/recommendations/build_pipelines_2/pipeline_instructions_2_3/pipeline_secret_scanning.yml +56 -0
  75. gitlabcis/recommendations/build_pipelines_2/pipeline_instructions_2_3/pipeline_vuln_scanning.yml +44 -0
  76. gitlabcis/recommendations/build_pipelines_2/pipeline_instructions_2_3/readme.md +16 -0
  77. gitlabcis/recommendations/build_pipelines_2/pipeline_instructions_2_3/secure_pipeline_output.yml +52 -0
  78. gitlabcis/recommendations/build_pipelines_2/pipeline_instructions_2_3/track_pipeline_files.yml +48 -0
  79. gitlabcis/recommendations/build_pipelines_2/pipeline_integrity_2_4/create_reproducible_artifacts.yml +52 -0
  80. gitlabcis/recommendations/build_pipelines_2/pipeline_integrity_2_4/lock_dependencies.yml +59 -0
  81. gitlabcis/recommendations/build_pipelines_2/pipeline_integrity_2_4/pipeline_produces_sbom.yml +81 -0
  82. gitlabcis/recommendations/build_pipelines_2/pipeline_integrity_2_4/pipeline_signs_sbom.yml +38 -0
  83. gitlabcis/recommendations/build_pipelines_2/pipeline_integrity_2_4/readme.md +14 -0
  84. gitlabcis/recommendations/build_pipelines_2/pipeline_integrity_2_4/sign_artifacts.yml +35 -0
  85. gitlabcis/recommendations/build_pipelines_2/pipeline_integrity_2_4/validate_dependencies.yml +63 -0
  86. gitlabcis/recommendations/build_pipelines_2/readme.md +12 -0
  87. gitlabcis/recommendations/dependencies_3/readme.md +10 -0
  88. gitlabcis/recommendations/dependencies_3/third_party_packages_3_1/define_package_managers.yml +84 -0
  89. gitlabcis/recommendations/dependencies_3/third_party_packages_3_1/dependency_sbom.yml +84 -0
  90. gitlabcis/recommendations/dependencies_3/third_party_packages_3_1/monitor_dependencies.yml +61 -0
  91. gitlabcis/recommendations/dependencies_3/third_party_packages_3_1/packages_over_60_days_old.yml +95 -0
  92. gitlabcis/recommendations/dependencies_3/third_party_packages_3_1/pin_dependency_version.yml +48 -0
  93. gitlabcis/recommendations/dependencies_3/third_party_packages_3_1/readme.md +14 -0
  94. gitlabcis/recommendations/dependencies_3/third_party_packages_3_1/third_party_sbom_required.yml +70 -0
  95. gitlabcis/recommendations/dependencies_3/third_party_packages_3_1/verify_artifacts.yml +45 -0
  96. gitlabcis/recommendations/dependencies_3/third_party_packages_3_1/verify_signed_metadata.yml +41 -0
  97. gitlabcis/recommendations/dependencies_3/validate_packages_3_2/org_wide_dependency_policy.yml +47 -0
  98. gitlabcis/recommendations/dependencies_3/validate_packages_3_2/package_license_scanning.yml +47 -0
  99. gitlabcis/recommendations/dependencies_3/validate_packages_3_2/package_ownership_change.yml +42 -0
  100. gitlabcis/recommendations/dependencies_3/validate_packages_3_2/package_vuln_scanning.yml +62 -0
  101. gitlabcis/recommendations/dependencies_3/validate_packages_3_2/readme.md +10 -0
  102. gitlabcis/recommendations/deployment_5/deployment_configuration_5_1/audit_deployment_config.yml +46 -0
  103. gitlabcis/recommendations/deployment_5/deployment_configuration_5_1/limit_deployment_config_access.yml +51 -0
  104. gitlabcis/recommendations/deployment_5/deployment_configuration_5_1/pin_deployment_config_manifests.yml +59 -0
  105. gitlabcis/recommendations/deployment_5/deployment_configuration_5_1/readme.md +13 -0
  106. gitlabcis/recommendations/deployment_5/deployment_configuration_5_1/scan_iac.yml +72 -0
  107. gitlabcis/recommendations/deployment_5/deployment_configuration_5_1/secret_scan_deployment_config.yml +45 -0
  108. gitlabcis/recommendations/deployment_5/deployment_configuration_5_1/separate_deployment_config.yml +50 -0
  109. gitlabcis/recommendations/deployment_5/deployment_configuration_5_1/verify_deployment_config.yml +49 -0
  110. gitlabcis/recommendations/deployment_5/deployment_environment_5_2/automate_deployment.yml +47 -0
  111. gitlabcis/recommendations/deployment_5/deployment_environment_5_2/disable_default_passwords.yml +63 -0
  112. gitlabcis/recommendations/deployment_5/deployment_environment_5_2/limit_prod_access.yml +45 -0
  113. gitlabcis/recommendations/deployment_5/deployment_environment_5_2/readme.md +12 -0
  114. gitlabcis/recommendations/deployment_5/deployment_environment_5_2/reproducible_deployment.yml +50 -0
  115. gitlabcis/recommendations/deployment_5/readme.md +10 -0
  116. gitlabcis/recommendations/readme.md +24 -0
  117. gitlabcis/recommendations/source_code_1/code_changes_1_1/audit_branch_protections.yml +56 -0
  118. gitlabcis/recommendations/source_code_1/code_changes_1_1/auto_risk_scan_merges.yml +62 -0
  119. gitlabcis/recommendations/source_code_1/code_changes_1_1/branch_protections_for_admins.yml +60 -0
  120. gitlabcis/recommendations/source_code_1/code_changes_1_1/branches_updated_before_merging.yml +56 -0
  121. gitlabcis/recommendations/source_code_1/code_changes_1_1/checks_pass_before_merging.yml +57 -0
  122. gitlabcis/recommendations/source_code_1/code_changes_1_1/code_approval_dismissals.yml +62 -0
  123. gitlabcis/recommendations/source_code_1/code_changes_1_1/code_approvals.yml +65 -0
  124. gitlabcis/recommendations/source_code_1/code_changes_1_1/code_changes_require_code_owners.yml +68 -0
  125. gitlabcis/recommendations/source_code_1/code_changes_1_1/code_dismissal_restrictions.yml +69 -0
  126. gitlabcis/recommendations/source_code_1/code_changes_1_1/code_owners.yml +61 -0
  127. gitlabcis/recommendations/source_code_1/code_changes_1_1/code_tracing.yml +52 -0
  128. gitlabcis/recommendations/source_code_1/code_changes_1_1/comments_resolved_before_merging.yml +59 -0
  129. gitlabcis/recommendations/source_code_1/code_changes_1_1/commits_must_be_signed_before_merging.yml +63 -0
  130. gitlabcis/recommendations/source_code_1/code_changes_1_1/default_branch_protected.yml +85 -0
  131. gitlabcis/recommendations/source_code_1/code_changes_1_1/deny_branch_deletions.yml +76 -0
  132. gitlabcis/recommendations/source_code_1/code_changes_1_1/ensure_force_push_is_denied.yml +59 -0
  133. gitlabcis/recommendations/source_code_1/code_changes_1_1/linear_history_required.yml +56 -0
  134. gitlabcis/recommendations/source_code_1/code_changes_1_1/merging_restrictions.yml +65 -0
  135. gitlabcis/recommendations/source_code_1/code_changes_1_1/readme.md +26 -0
  136. gitlabcis/recommendations/source_code_1/code_changes_1_1/stale_branch_reviews.yml +72 -0
  137. gitlabcis/recommendations/source_code_1/code_changes_1_1/version_control.yml +45 -0
  138. gitlabcis/recommendations/source_code_1/code_risks_1_5/dast_api_scanning.yml +50 -0
  139. gitlabcis/recommendations/source_code_1/code_risks_1_5/dast_web_scanning.yml +51 -0
  140. gitlabcis/recommendations/source_code_1/code_risks_1_5/dependency_scanning.yml +84 -0
  141. gitlabcis/recommendations/source_code_1/code_risks_1_5/enable_secret_detection.yml +45 -0
  142. gitlabcis/recommendations/source_code_1/code_risks_1_5/license_scanning.yml +47 -0
  143. gitlabcis/recommendations/source_code_1/code_risks_1_5/readme.md +14 -0
  144. gitlabcis/recommendations/source_code_1/code_risks_1_5/secure_iac_instructions.yml +81 -0
  145. gitlabcis/recommendations/source_code_1/code_risks_1_5/secure_pipeline_instructions.yml +62 -0
  146. gitlabcis/recommendations/source_code_1/code_risks_1_5/vulnerability_scanning.yml +48 -0
  147. gitlabcis/recommendations/source_code_1/contribution_access_1_3/domain_verification.yml +65 -0
  148. gitlabcis/recommendations/source_code_1/contribution_access_1_3/ensure_2_admins_per_repo.yml +56 -0
  149. gitlabcis/recommendations/source_code_1/contribution_access_1_3/limit_top_level_group_creation.yml +61 -0
  150. gitlabcis/recommendations/source_code_1/contribution_access_1_3/limit_user_registration_domain.yml +58 -0
  151. gitlabcis/recommendations/source_code_1/contribution_access_1_3/minimum_number_of_admins.yml +56 -0
  152. gitlabcis/recommendations/source_code_1/contribution_access_1_3/org_provided_ssh_certs.yml +70 -0
  153. gitlabcis/recommendations/source_code_1/contribution_access_1_3/readme.md +21 -0
  154. gitlabcis/recommendations/source_code_1/contribution_access_1_3/require_mfa_at_org_level.yml +89 -0
  155. gitlabcis/recommendations/source_code_1/contribution_access_1_3/require_mfa_for_contributors.yml +76 -0
  156. gitlabcis/recommendations/source_code_1/contribution_access_1_3/restrict_ip_addresses.yml +84 -0
  157. gitlabcis/recommendations/source_code_1/contribution_access_1_3/review_and_remove_inactive_users.yml +62 -0
  158. gitlabcis/recommendations/source_code_1/contribution_access_1_3/scm_notification_restriction.yml +46 -0
  159. gitlabcis/recommendations/source_code_1/contribution_access_1_3/strict_permissions_for_repo.yml +62 -0
  160. gitlabcis/recommendations/source_code_1/contribution_access_1_3/track_code_anomalies.yml +43 -0
  161. gitlabcis/recommendations/source_code_1/readme.md +13 -0
  162. gitlabcis/recommendations/source_code_1/repository_management_1_2/limit_issue_deletions.yml +57 -0
  163. gitlabcis/recommendations/source_code_1/repository_management_1_2/limit_repo_creations.yml +64 -0
  164. gitlabcis/recommendations/source_code_1/repository_management_1_2/limit_repo_deletions.yml +57 -0
  165. gitlabcis/recommendations/source_code_1/repository_management_1_2/public_repos_have_security_file.yml +59 -0
  166. gitlabcis/recommendations/source_code_1/repository_management_1_2/readme.md +15 -0
  167. gitlabcis/recommendations/source_code_1/repository_management_1_2/review_and_archive_stale_repos.yml +65 -0
  168. gitlabcis/recommendations/source_code_1/repository_management_1_2/track_forks.yml +74 -0
  169. gitlabcis/recommendations/source_code_1/repository_management_1_2/track_project_visibility_status.yml +74 -0
  170. gitlabcis/recommendations/source_code_1/third_party_1_4/README.md +12 -0
  171. gitlabcis/recommendations/source_code_1/third_party_1_4/admin_approval_for_app_installs.yml +83 -0
  172. gitlabcis/recommendations/source_code_1/third_party_1_4/least_privilge_app_permissions.yml +103 -0
  173. gitlabcis/recommendations/source_code_1/third_party_1_4/secure_webhooks.yml +73 -0
  174. gitlabcis/recommendations/source_code_1/third_party_1_4/stale_app_reviews.yml +66 -0
  175. gitlabcis/recommendations/template.yml +30 -0
  176. gitlabcis/tests/__init__.py +0 -0
  177. gitlabcis/tests/input/__init__.py +0 -0
  178. gitlabcis/tests/input/conftest.py +29 -0
  179. gitlabcis/tests/input/no_input_test.py +82 -0
  180. gitlabcis/tests/input/switch_test.py +19 -0
  181. gitlabcis/tests/input/version_test.py +7 -0
  182. gitlabcis/tests/unit/__init__.py +0 -0
  183. gitlabcis/tests/unit/benchmarks/artifacts_4/access_to_artifacts_4_2_test.py +131 -0
  184. gitlabcis/tests/unit/benchmarks/artifacts_4/origin_traceability_4_4_test.py +15 -0
  185. gitlabcis/tests/unit/benchmarks/artifacts_4/package_registries_4_3_test.py +102 -0
  186. gitlabcis/tests/unit/benchmarks/artifacts_4/verification_4_1_test.py +78 -0
  187. gitlabcis/tests/unit/benchmarks/build_pipelines_2/build_environment_2_1_test.py +239 -0
  188. gitlabcis/tests/unit/benchmarks/build_pipelines_2/build_worker_2_2_test.py +105 -0
  189. gitlabcis/tests/unit/benchmarks/build_pipelines_2/pipeline_instructions_2_3_test.py +340 -0
  190. gitlabcis/tests/unit/benchmarks/build_pipelines_2/pipeline_integrity_2_4_test.py +115 -0
  191. gitlabcis/tests/unit/benchmarks/conftest.py +47 -0
  192. gitlabcis/tests/unit/benchmarks/dependencies_3/third_party_packages_3_1_test.py +135 -0
  193. gitlabcis/tests/unit/benchmarks/dependencies_3/validate_packages_3_2_test.py +171 -0
  194. gitlabcis/tests/unit/benchmarks/deployment_5/deployment_configuration_5_1_test.py +140 -0
  195. gitlabcis/tests/unit/benchmarks/deployment_5/deployment_environment_5_2_test.py +60 -0
  196. gitlabcis/tests/unit/benchmarks/function_test.py +24 -0
  197. gitlabcis/tests/unit/benchmarks/source_code_1/code_changes_1_1_test.py +565 -0
  198. gitlabcis/tests/unit/benchmarks/source_code_1/code_risks_1_5_test.py +419 -0
  199. gitlabcis/tests/unit/benchmarks/source_code_1/contribution_access_1_3_test.py +265 -0
  200. gitlabcis/tests/unit/benchmarks/source_code_1/repository_management_1_2_test.py +142 -0
  201. gitlabcis/tests/unit/benchmarks/source_code_1/third_party_1_4_test.py +119 -0
  202. gitlabcis/tests/unit/conftest.py +94 -0
  203. gitlabcis/tests/unit/log/log_test.py +23 -0
  204. gitlabcis/tests/unit/utils/argfilters_test.py +9 -0
  205. gitlabcis/tests/unit/utils/ci_test.py +156 -0
  206. gitlabcis/tests/unit/utils/output_test.py +95 -0
  207. gitlabcis/tests/unit/utils/utils_general_test.py +149 -0
  208. gitlabcis/tests/unit/utils/version_test.py +11 -0
  209. gitlabcis/tests/unit/yaml/bad_file_test.py +15 -0
  210. gitlabcis/tests/unit/yaml/recommendation_test.py +123 -0
  211. gitlabcis/utils/__init__.py +146 -0
  212. gitlabcis/utils/ci.py +132 -0
  213. gitlabcis-1.3.2.dist-info/LICENSE +21 -0
  214. gitlabcis-1.3.2.dist-info/METADATA +241 -0
  215. gitlabcis-1.3.2.dist-info/RECORD +218 -0
  216. gitlabcis-1.3.2.dist-info/WHEEL +5 -0
  217. gitlabcis-1.3.2.dist-info/entry_points.txt +2 -0
  218. gitlabcis-1.3.2.dist-info/top_level.txt +1 -0
@@ -0,0 +1,665 @@
1
+ # -------------------------------------------------------------------------
2
+
3
+
4
+ def version_control(glEntity, glObject, **kwargs):
5
+ """
6
+ id: 1.1.1
7
+ title: Ensure any changes to code are tracked in a version control
8
+ platform
9
+ """
10
+
11
+ # previously project has been validated to be a valid gitlab project
12
+ if glEntity is not None:
13
+ return {True: 'Using GitLab as version control'}
14
+
15
+ return {False: 'Not using GitLab as version control'}
16
+
17
+ # -------------------------------------------------------------------------
18
+
19
+
20
+ def code_tracing(glEntity, glObject, **kwargs):
21
+ """
22
+ id: 1.1.2
23
+ title: Ensure any change to code can be traced back to its associated
24
+ task
25
+ """
26
+
27
+ from gitlab.exceptions import (GitlabAuthenticationError, GitlabGetError,
28
+ GitlabHttpError, GitlabListError)
29
+
30
+ try:
31
+ if len(glEntity.issues.list(get_all=False)) > 0:
32
+ return {True: 'Issues are used in the project'}
33
+
34
+ return {False: 'Issues are not used in the project'}
35
+
36
+ except (GitlabHttpError, GitlabGetError, GitlabAuthenticationError,
37
+ GitlabListError) as e:
38
+ if e.response_code in [401, 403]:
39
+ return {None: 'Insufficient permissions'}
40
+
41
+ # -------------------------------------------------------------------------
42
+
43
+
44
+ def code_approvals(glEntity, glObject, **kwargs):
45
+ """
46
+ id: 1.1.3
47
+ title: Ensure any change to code receives approval of two strongly
48
+ authenticated users
49
+ """
50
+
51
+ from gitlab.exceptions import (GitlabAuthenticationError, GitlabGetError,
52
+ GitlabHttpError, GitlabListError)
53
+
54
+ try:
55
+ for approval in glEntity.approvalrules.list(get_all=True):
56
+ if approval.approvals_required >= 2:
57
+ return {True: '2 approvals are required for code changes'}
58
+
59
+ return {False: '2 approvals are required for code changes'}
60
+
61
+ except (GitlabHttpError, GitlabGetError, GitlabAuthenticationError,
62
+ GitlabListError) as e:
63
+ if e.response_code in [401, 403]:
64
+ return {None: 'Insufficient permissions'}
65
+
66
+ # -------------------------------------------------------------------------
67
+
68
+
69
+ def code_approval_dismissals(glEntity, glObject, **kwargs):
70
+ """
71
+ id: 1.1.4
72
+ title: Ensure previous approvals are dismissed when updates are
73
+ introduced to a code change proposal
74
+ """
75
+
76
+ from gitlab.exceptions import (GitlabAuthenticationError, GitlabGetError,
77
+ GitlabHttpError)
78
+
79
+ try:
80
+ mrApprovalSettings = glEntity.approvals.get()
81
+
82
+ if mrApprovalSettings.reset_approvals_on_push is True:
83
+ return {True: 'Approvals reset on push'}
84
+
85
+ return {False: 'Approvals not reset on push'}
86
+
87
+ except (GitlabHttpError, GitlabGetError, GitlabAuthenticationError) as e:
88
+ if e.response_code in [401, 403]:
89
+ return {None: 'Insufficient permissions'}
90
+
91
+ # -------------------------------------------------------------------------
92
+
93
+
94
+ def code_dismissal_restrictions(glEntity, glObject, **kwargs):
95
+ """
96
+ id: 1.1.5
97
+ title: Ensure there are restrictions on who can dismiss code change
98
+ reviews
99
+ """
100
+
101
+ from gitlab.exceptions import (GitlabAuthenticationError, GitlabGetError,
102
+ GitlabHttpError, GitlabListError)
103
+
104
+ try:
105
+ protectedBranches = glEntity.protectedbranches.list(get_all=False)
106
+
107
+ # by default a project sets only "Maintainers" for the users
108
+ # for both merge / push approvals
109
+
110
+ _userRoles = list(set(
111
+ level.get('access_level_description')
112
+ for branch in protectedBranches
113
+ for key in ['merge_access_levels', 'push_access_levels']
114
+ for levels in [getattr(branch, key, [])]
115
+ for level in levels
116
+ ))
117
+
118
+ # if the defaults are still set, fail the check
119
+ if _userRoles:
120
+ if len(_userRoles) == 1 and _userRoles[0] == 'Maintainers':
121
+ return {
122
+ False: 'No restrictions on who can dismiss code changes'}
123
+ else:
124
+ return {False: 'No restrictions on who can dismiss code changes'}
125
+
126
+ # this will return true if someone has altered the defaults set:
127
+ return {True: 'Restrictions set on who can dismiss code changes'}
128
+
129
+ except (GitlabHttpError, GitlabGetError, GitlabAuthenticationError,
130
+ GitlabListError) as e:
131
+ if e.response_code in [401, 403]:
132
+ return {None: 'Insufficient permissions'}
133
+
134
+ # -------------------------------------------------------------------------
135
+
136
+
137
+ def code_owners(glEntity, glObject, **kwargs):
138
+ """
139
+ id: 1.1.6
140
+ title: Ensure code owners are set for extra sensitive code or
141
+ configuration
142
+ """
143
+
144
+ from gitlab.exceptions import (GitlabAuthenticationError, GitlabGetError,
145
+ GitlabHttpError)
146
+
147
+ # as per the docs, the CODEOWNERS file can live in multiple places:
148
+ # https://docs.gitlab.com/ee/user/project/codeowners/
149
+
150
+ _dirPaths = ['', '.gitlab', 'docs']
151
+
152
+ # if the CODEOWNERS file is present, pass the check:
153
+ for dirPath in _dirPaths:
154
+
155
+ # some repos may not have these paths, so exclude them:
156
+ try:
157
+ _files = glEntity.repository_tree(path=dirPath)
158
+
159
+ except (GitlabHttpError, GitlabGetError,
160
+ GitlabAuthenticationError) as e:
161
+
162
+ if e.response_code == 404:
163
+ continue
164
+
165
+ if e.response_code in [401, 403]:
166
+ return {None: 'Insufficient permissions'}
167
+
168
+ return {None: 'Unknown error'}
169
+
170
+ for _file in _files:
171
+
172
+ if _file.get('name') == 'CODEOWNERS':
173
+ return {True: 'CODEOWNERS file present'}
174
+
175
+ return {False: 'CODEOWNERS file not present'}
176
+
177
+ # -------------------------------------------------------------------------
178
+
179
+
180
+ def code_changes_require_code_owners(glEntity, glObject, **kwargs):
181
+ """
182
+ id: 1.1.7
183
+ title: Ensure code owner's review is required when a change affects
184
+ owned code
185
+ """
186
+
187
+ from gitlab.exceptions import (GitlabAuthenticationError, GitlabGetError,
188
+ GitlabHttpError)
189
+
190
+ try:
191
+ defaultBranch = glEntity.protectedbranches.get(glEntity.default_branch)
192
+
193
+ if defaultBranch is None:
194
+ return {False: 'Default branch is not protected'}
195
+
196
+ if defaultBranch.code_owner_approval_required is True:
197
+ return {True: 'CODEOWNERS approval is required'}
198
+
199
+ return {False: 'CODEOWNERS approval is not configured'}
200
+
201
+ except (GitlabHttpError, GitlabGetError, GitlabAuthenticationError) as e:
202
+ if e.response_code == 403 and e.error_message == '403 Forbidden':
203
+ return {None: 'Insufficient permissions'}
204
+
205
+ if e.response_code == 404:
206
+ return {False: 'Default branch is not protected'}
207
+
208
+ # -------------------------------------------------------------------------
209
+
210
+
211
+ def stale_branch_reviews(glEntity, glObject, **kwargs):
212
+ """
213
+ id: 1.1.8
214
+ title: Ensure inactive branches are periodically reviewed and removed
215
+ """
216
+
217
+ from datetime import datetime
218
+
219
+ from dateutil.relativedelta import relativedelta
220
+ from gitlab.exceptions import (GitlabAuthenticationError, GitlabGetError,
221
+ GitlabHttpError, GitlabListError)
222
+
223
+ try:
224
+ _staleBranches = []
225
+
226
+ for branch in glEntity.branches.list(get_all=True):
227
+ _commitDate = datetime.strptime(
228
+ branch.commit.get('committed_date'),
229
+ '%Y-%m-%dT%H:%M:%S.%f%z'
230
+ ).replace(tzinfo=None)
231
+
232
+ if relativedelta(datetime.now(), _commitDate).months > 3:
233
+ _staleBranches.append(branch.name)
234
+
235
+ if len(_staleBranches) == 0:
236
+ return {True: 'No stale branches found'}
237
+
238
+ return {False: 'Found stale branches'}
239
+
240
+ except (GitlabHttpError, GitlabGetError, GitlabAuthenticationError,
241
+ GitlabListError) as e:
242
+ if e.response_code in [401, 403]:
243
+ return {None: 'Insufficient permissions'}
244
+
245
+ # -------------------------------------------------------------------------
246
+
247
+
248
+ def checks_pass_before_merging(glEntity, glObject, **kwargs):
249
+ """
250
+ id: 1.1.9
251
+ title: Ensure all checks have passed before merging new code
252
+ """
253
+
254
+ from gitlab.exceptions import (GitlabAuthenticationError, GitlabGetError,
255
+ GitlabHttpError)
256
+
257
+ # bool value if box is checked in Settings -> Merge Requests:
258
+ try:
259
+ _allowMerging = glEntity.only_allow_merge_if_all_status_checks_passed
260
+
261
+ if _allowMerging is True:
262
+ return {True: 'All checks must pass before merging'}
263
+ else:
264
+ return {False: 'All checks do not need to pass before merging'}
265
+
266
+ except (GitlabHttpError, GitlabGetError, GitlabAuthenticationError) as e:
267
+ if e.response_code in [401, 403]:
268
+ return {None: 'Insufficient permissions'}
269
+
270
+ # if a user is on a free tier plan, this attribute will not exist:
271
+ except AttributeError:
272
+ return {None: 'The project is not on an eligible plan'}
273
+
274
+ # -------------------------------------------------------------------------
275
+
276
+
277
+ def branches_updated_before_merging(glEntity, glObject, **kwargs):
278
+ """
279
+ id: 1.1.10
280
+ title: Ensure open Git branches are up to date before they can be
281
+ merged into code base
282
+ """
283
+
284
+ from gitlab.exceptions import (GitlabAuthenticationError, GitlabGetError,
285
+ GitlabHttpError)
286
+
287
+ try:
288
+ if glEntity.merge_method in ['rebase_merge', 'ff']:
289
+ return {True: 'Merge methods set'}
290
+
291
+ return {False: 'Merge methods not set'}
292
+
293
+ except (GitlabHttpError, GitlabGetError, GitlabAuthenticationError) as e:
294
+ if e.response_code in [401, 403]:
295
+ return {None: 'Insufficient permissions'}
296
+
297
+ # this throws an attr error if accessed anonymously (pytest no auth)
298
+ except AttributeError:
299
+ return {None: 'Insufficient permissions'}
300
+
301
+ # -------------------------------------------------------------------------
302
+
303
+
304
+ def comments_resolved_before_merging(glEntity, glObject, **kwargs):
305
+ """
306
+ id: 1.1.11
307
+ title: Ensure all open comments are resolved before allowing code
308
+ change merging
309
+ """
310
+
311
+ from gitlab.exceptions import (GitlabAuthenticationError, GitlabGetError,
312
+ GitlabHttpError)
313
+
314
+ try:
315
+ # bool value if box is checked in Settings -> Merge Requests:
316
+ try:
317
+ _dR = glEntity.only_allow_merge_if_all_discussions_are_resolved
318
+ # this throws an attr error if accessed anonymously (pytest no auth)
319
+ except AttributeError:
320
+ return {None: 'Insufficient permissions'}
321
+
322
+ if _dR is True:
323
+ return {True: 'All comments must be resolved before merging'}
324
+
325
+ elif _dR is False:
326
+ return {
327
+ False: 'All comments do not need to be resolved before merging'
328
+ }
329
+
330
+ except (GitlabHttpError, GitlabGetError, GitlabAuthenticationError) as e:
331
+ if e.response_code in [401, 403]:
332
+ return {None: 'Insufficient permissions'}
333
+
334
+ # -------------------------------------------------------------------------
335
+
336
+
337
+ def commits_must_be_signed_before_merging(glEntity, glObject, **kwargs):
338
+ """
339
+ id: 1.1.12
340
+ title: Ensure verification of signed commits for new changes before
341
+ merging
342
+ """
343
+
344
+ from gitlab.exceptions import (GitlabAuthenticationError, GitlabGetError,
345
+ GitlabHttpError)
346
+
347
+ try:
348
+ pushRules = glEntity.pushrules.get()
349
+
350
+ if pushRules.reject_unsigned_commits is True:
351
+ return {True: 'Rejecting unsigned commits'}
352
+
353
+ return {False: 'Unsigned commits are not rejected'}
354
+
355
+ except (GitlabHttpError, GitlabGetError, GitlabAuthenticationError) as e:
356
+ if e.response_code in [401, 403]:
357
+ return {None: 'Insufficient permissions'}
358
+
359
+ if e.response_code == 404:
360
+ return {False: 'No push rules found'}
361
+
362
+ # -------------------------------------------------------------------------
363
+
364
+
365
+ def linear_history_required(glEntity, glObject, **kwargs):
366
+ """
367
+ id: 1.1.13
368
+ title: Ensure linear history is required
369
+ """
370
+
371
+ from gitlab.exceptions import (GitlabAuthenticationError, GitlabGetError,
372
+ GitlabHttpError)
373
+
374
+ try:
375
+ if glEntity.merge_method not in ['rebase_merge', 'merge']:
376
+ return {True: 'Merge method set'}
377
+
378
+ return {False: 'Merge method not set'}
379
+
380
+ except (GitlabHttpError, GitlabGetError, GitlabAuthenticationError) as e:
381
+ if e.response_code in [401, 403]:
382
+ return {None: 'Insufficient permissions'}
383
+
384
+ # this throws an attr error if accessed anonymously (pytest no auth)
385
+ except AttributeError:
386
+ return {None: 'Insufficient permissions'}
387
+
388
+ # -------------------------------------------------------------------------
389
+
390
+
391
+ def branch_protections_for_admins(glEntity, glObject, **kwargs):
392
+ """
393
+ id: 1.1.14
394
+ title: Ensure branch protection rules are enforced for administrators
395
+ """
396
+
397
+ from gitlab.exceptions import (GitlabAuthenticationError, GitlabGetError,
398
+ GitlabHttpError)
399
+
400
+ try:
401
+ settings = glObject.settings.get()
402
+
403
+ if settings.group_owners_can_manage_default_branch_protection is False:
404
+ return {
405
+ True: 'Group owners cannot manage default branch protection'}
406
+
407
+ return {False: 'Group owners can manage default branch protection'}
408
+
409
+ except (GitlabHttpError, GitlabGetError, GitlabAuthenticationError) as e:
410
+ if e.response_code in [401, 403]:
411
+ return {None: 'Insufficient permissions'}
412
+
413
+ # -------------------------------------------------------------------------
414
+
415
+
416
+ def merging_restrictions(glEntity, glObject, **kwargs):
417
+ """
418
+ id: 1.1.15
419
+ title: Ensure pushing or merging of new code is restricted to specific
420
+ individuals or teams
421
+ """
422
+
423
+ from gitlab.exceptions import (GitlabAuthenticationError, GitlabGetError,
424
+ GitlabHttpError, GitlabListError)
425
+
426
+ try:
427
+ protectedBranches = glEntity.protectedbranches.list(get_all=True)
428
+
429
+ if len(protectedBranches) == 0:
430
+ return {False: 'No protected branches found'}
431
+
432
+ for branch in protectedBranches:
433
+
434
+ if branch.allow_force_push is True:
435
+ return {False: 'Protected branches allow force push'}
436
+
437
+ return {True: 'Protected branches do not allow force push'}
438
+
439
+ except (GitlabHttpError, GitlabGetError, GitlabAuthenticationError,
440
+ GitlabListError) as e:
441
+ if e.response_code in [401, 403]:
442
+ return {None: 'Insufficient permissions'}
443
+
444
+ # -------------------------------------------------------------------------
445
+
446
+
447
+ def ensure_force_push_is_denied(glEntity, glObject, **kwargs):
448
+ """
449
+ id: 1.1.16
450
+ title: Ensure force push code to branches is denied
451
+ """
452
+
453
+ from gitlab.exceptions import (GitlabAuthenticationError, GitlabGetError,
454
+ GitlabHttpError)
455
+
456
+ try:
457
+ defaultBranch = glEntity.protectedbranches.get(glEntity.default_branch)
458
+
459
+ if defaultBranch is not None \
460
+ and defaultBranch.allow_force_push is False:
461
+ return {
462
+ True: 'Default branch is protected and does not allow '
463
+ 'force push'
464
+ }
465
+
466
+ return {False: 'Default branch is not protected or allows '
467
+ 'force push'}
468
+
469
+ except (GitlabHttpError, GitlabGetError, GitlabAuthenticationError) as e:
470
+ # if we don't have access, or the default branch is not protected:
471
+ if e.response_code in [401, 403, 404]:
472
+ return {None: 'Insufficient permissions'}
473
+
474
+ # -------------------------------------------------------------------------
475
+
476
+
477
+ def deny_branch_deletions(glEntity, glObject, **kwargs):
478
+ """
479
+ id: 1.1.17
480
+ title: Ensure branch deletions are denied
481
+ """
482
+
483
+ from gitlab.exceptions import (GitlabAuthenticationError, GitlabGetError,
484
+ GitlabHttpError, GitlabListError)
485
+
486
+ try:
487
+ protectedBranches = glEntity.protectedbranches.list(get_all=False)
488
+
489
+ if len(protectedBranches) == 0:
490
+ return {False: 'No protected branches found'}
491
+
492
+ return {True: 'Protected branches found'}
493
+
494
+ except (GitlabHttpError, GitlabGetError, GitlabAuthenticationError,
495
+ GitlabListError) as e:
496
+ if e.response_code in [401, 403]:
497
+ return {None: 'Insufficient permissions'}
498
+
499
+ # -------------------------------------------------------------------------
500
+
501
+
502
+ def auto_risk_scan_merges(glEntity, glObject, **kwargs):
503
+ """
504
+ id: 1.1.18
505
+ title: Ensure any merging of code is automatically scanned for risks
506
+ """
507
+
508
+ import yaml
509
+ from gitlab.exceptions import (GitlabAuthenticationError, GitlabGetError,
510
+ GitlabHttpError)
511
+ from gql import Client, gql
512
+ from gql.transport.exceptions import (TransportAlreadyConnected,
513
+ TransportServerError)
514
+ from gql.transport.requests import RequestsHTTPTransport
515
+ from graphql import GraphQLError
516
+
517
+ try:
518
+
519
+ variables = {
520
+ 'fullPath': glEntity.path_with_namespace
521
+ }
522
+
523
+ except (GitlabHttpError, GitlabGetError, GitlabAuthenticationError) as e:
524
+ if e.response_code in [401, 403]:
525
+ return {None: 'Insufficient permissions'}
526
+
527
+ client = Client(
528
+ transport=RequestsHTTPTransport(
529
+ url=kwargs.get('graphQLEndpoint'),
530
+ headers=kwargs.get('graphQLHeaders'),
531
+ use_json=True
532
+ ),
533
+ fetch_schema_from_transport=True
534
+ )
535
+
536
+ query = gql('''
537
+ query GetSecurityScanners($fullPath: ID!) {
538
+ project(fullPath: $fullPath) {
539
+ scanExecutionPolicies {
540
+ nodes {
541
+ name
542
+ enabled
543
+ yaml
544
+ }
545
+ }
546
+ }
547
+ }
548
+ ''')
549
+
550
+ try:
551
+
552
+ results = client.execute(query, variable_values=variables)
553
+
554
+ except (GraphQLError, TransportServerError, TransportAlreadyConnected):
555
+ return {None: 'Error: Issue with GraphQL Query'}
556
+
557
+ # pytest no auth:
558
+ except AttributeError:
559
+ return {None: 'Insufficient permissions'}
560
+
561
+ try:
562
+ required_scans = [
563
+ 'dast', 'secret_detection', 'cluster_image_scanning',
564
+ 'container_scanning', 'sast', 'sast_iac', 'dependency_scanning'
565
+ ]
566
+
567
+ scans_found = set()
568
+ secret_detection_policy_found = False
569
+ for policy in results['project']['scanExecutionPolicies']['nodes']:
570
+ if policy.get('enabled') is True:
571
+ policy_yaml = yaml.safe_load(policy.get('yaml', ''))
572
+ actions = policy_yaml.get('actions', [])
573
+ rules = policy_yaml.get('rules', [])
574
+ for action in actions:
575
+ scans_found.add(action.get('scan'))
576
+ if action.get('scan') == 'secret_detection':
577
+ for rule in rules:
578
+ if (
579
+ rule.get('type') == 'pipeline'
580
+ and '*' in rule.get('branches', [])
581
+ ):
582
+ secret_detection_policy_found = True
583
+ missing_scans = [
584
+ scan for scan in required_scans
585
+ if scan not in scans_found
586
+ ]
587
+ if secret_detection_policy_found:
588
+ if missing_scans:
589
+ return {
590
+ True: (
591
+ 'Scan Execution Policy for secret_detection is '
592
+ 'enabled and triggers for all pipelines and '
593
+ 'branches. Other missing scans for manual review:'
594
+ f'{", ".join(missing_scans)}'
595
+ )
596
+ }
597
+ else:
598
+ return {
599
+ True: (
600
+ 'Scan Execution Policy for secret_detection is '
601
+ 'enabled and triggers for all pipelines and '
602
+ 'branches. All required scans are covered.'
603
+ )
604
+ }
605
+ else:
606
+ return {
607
+ False: (
608
+ 'Scan Execution Policy for secret_detection '
609
+ 'is not enabled to trigger for all pipelines '
610
+ 'and branches. Other missing scans for manual '
611
+ f'review: {", ".join(missing_scans)}'
612
+ )
613
+ }
614
+
615
+ except KeyError:
616
+ return {False: 'Scan Execution Policy was not found'}
617
+
618
+ # -------------------------------------------------------------------------
619
+
620
+
621
+ def audit_branch_protections(glEntity, glObject, **kwargs):
622
+ """
623
+ id: 1.1.19
624
+ title: Ensure any changes to branch protection rules are audited
625
+ """
626
+
627
+ from gitlab.exceptions import (GitlabAuthenticationError, GitlabGetError,
628
+ GitlabHttpError, GitlabLicenseError)
629
+
630
+ try:
631
+ if glObject.get_license().get('plan') in ['premium', 'ultimate']:
632
+ return {True: 'License allows audit on branch protections'}
633
+
634
+ return {False: 'License does not allow audit on branch protections'}
635
+
636
+ except (GitlabHttpError, GitlabGetError, GitlabLicenseError) as e:
637
+ if e.response_code == 403 and e.error_message == '403 Forbidden':
638
+ return {None: 'Insufficient permissions'}
639
+
640
+ except (GitlabAuthenticationError):
641
+ return {None: 'Insufficient permissions'}
642
+
643
+ # -------------------------------------------------------------------------
644
+
645
+
646
+ def default_branch_protected(glEntity, glObject, **kwargs):
647
+ """
648
+ id: 1.1.20
649
+ title: Ensure branch protection is enforced on the default branch
650
+ """
651
+
652
+ from gitlab.exceptions import (GitlabAuthenticationError, GitlabGetError,
653
+ GitlabHttpError)
654
+
655
+ try:
656
+ defaultBranch = glEntity.branches.get(glEntity.default_branch)
657
+
658
+ if defaultBranch.protected is True:
659
+ return {True: 'Default branch is protected'}
660
+
661
+ return {False: 'Default branch is not protected'}
662
+
663
+ except (GitlabHttpError, GitlabGetError, GitlabAuthenticationError) as e:
664
+ if e.response_code in [401, 403]:
665
+ return {None: 'Insufficient permissions'}