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.
- gitlabcis/__init__.py +12 -0
- gitlabcis/__main__.py +7 -0
- gitlabcis/benchmarks/__init__.py +8 -0
- gitlabcis/benchmarks/artifacts_4/__init__.py +4 -0
- gitlabcis/benchmarks/artifacts_4/access_to_artifacts_4_2.py +139 -0
- gitlabcis/benchmarks/artifacts_4/origin_traceability_4_4.py +11 -0
- gitlabcis/benchmarks/artifacts_4/package_registries_4_3.py +105 -0
- gitlabcis/benchmarks/artifacts_4/verification_4_1.py +83 -0
- gitlabcis/benchmarks/build_pipelines_2/__init__.py +4 -0
- gitlabcis/benchmarks/build_pipelines_2/build_environment_2_1.py +268 -0
- gitlabcis/benchmarks/build_pipelines_2/build_worker_2_2.py +129 -0
- gitlabcis/benchmarks/build_pipelines_2/pipeline_instructions_2_3.py +444 -0
- gitlabcis/benchmarks/build_pipelines_2/pipeline_integrity_2_4.py +146 -0
- gitlabcis/benchmarks/dependencies_3/__init__.py +2 -0
- gitlabcis/benchmarks/dependencies_3/third_party_packages_3_1.py +171 -0
- gitlabcis/benchmarks/dependencies_3/validate_packages_3_2.py +182 -0
- gitlabcis/benchmarks/deployment_5/__init__.py +2 -0
- gitlabcis/benchmarks/deployment_5/deployment_configuration_5_1.py +165 -0
- gitlabcis/benchmarks/deployment_5/deployment_environment_5_2.py +66 -0
- gitlabcis/benchmarks/source_code_1/__init__.py +6 -0
- gitlabcis/benchmarks/source_code_1/code_changes_1_1.py +665 -0
- gitlabcis/benchmarks/source_code_1/code_risks_1_5.py +506 -0
- gitlabcis/benchmarks/source_code_1/contribution_access_1_3.py +334 -0
- gitlabcis/benchmarks/source_code_1/repository_management_1_2.py +168 -0
- gitlabcis/benchmarks/source_code_1/third_party_1_4.py +139 -0
- gitlabcis/cli/__init__.py +0 -0
- gitlabcis/cli/log.py +30 -0
- gitlabcis/cli/main.py +541 -0
- gitlabcis/cli/output.py +151 -0
- gitlabcis/recommendations/artifacts_4/access_to_artifacts_4_2/external_auth_server.yml +51 -0
- gitlabcis/recommendations/artifacts_4/access_to_artifacts_4_2/limit_artifact_uploaders.yml +57 -0
- gitlabcis/recommendations/artifacts_4/access_to_artifacts_4_2/limit_certifying_artifacts.yml +53 -0
- gitlabcis/recommendations/artifacts_4/access_to_artifacts_4_2/minimum_package_registry_admins.yml +54 -0
- gitlabcis/recommendations/artifacts_4/access_to_artifacts_4_2/readme.md +14 -0
- gitlabcis/recommendations/artifacts_4/access_to_artifacts_4_2/require_mfa_to_package_registry.yml +52 -0
- gitlabcis/recommendations/artifacts_4/access_to_artifacts_4_2/restrict_anonymous_access.yml +67 -0
- gitlabcis/recommendations/artifacts_4/origin_traceability_4_4/artifact_origin_info.yml +56 -0
- gitlabcis/recommendations/artifacts_4/origin_traceability_4_4/readme.md +7 -0
- gitlabcis/recommendations/artifacts_4/package_registries_4_3/all_artifact_versions_signed.yml +70 -0
- gitlabcis/recommendations/artifacts_4/package_registries_4_3/audit_package_registry_config.yml +46 -0
- gitlabcis/recommendations/artifacts_4/package_registries_4_3/readme.md +12 -0
- gitlabcis/recommendations/artifacts_4/package_registries_4_3/secure_repo_webhooks.yml +50 -0
- gitlabcis/recommendations/artifacts_4/package_registries_4_3/validate_signed_artifacts_on_upload.yml +72 -0
- gitlabcis/recommendations/artifacts_4/readme.md +12 -0
- gitlabcis/recommendations/artifacts_4/verification_4_1/encrypt_artifacts_before_distribution.yml +47 -0
- gitlabcis/recommendations/artifacts_4/verification_4_1/only_authorized_platforms_can_decrypt_artifacts.yml +59 -0
- gitlabcis/recommendations/artifacts_4/verification_4_1/readme.md +11 -0
- gitlabcis/recommendations/artifacts_4/verification_4_1/sign_artifacts_in_build_pipeline.yml +40 -0
- gitlabcis/recommendations/build_pipelines_2/build_environment_2_1/authenticate_build_access.yml +55 -0
- gitlabcis/recommendations/build_pipelines_2/build_environment_2_1/build_automation.yml +54 -0
- gitlabcis/recommendations/build_pipelines_2/build_environment_2_1/build_env_admins.yml +55 -0
- gitlabcis/recommendations/build_pipelines_2/build_environment_2_1/build_logging.yml +49 -0
- gitlabcis/recommendations/build_pipelines_2/build_environment_2_1/disable_build_tools_default_passwords.yml +54 -0
- gitlabcis/recommendations/build_pipelines_2/build_environment_2_1/immutable_pipeline_infrastructure.yml +60 -0
- gitlabcis/recommendations/build_pipelines_2/build_environment_2_1/limit_build_access.yml +64 -0
- gitlabcis/recommendations/build_pipelines_2/build_environment_2_1/limit_build_secrets_scope.yml +56 -0
- gitlabcis/recommendations/build_pipelines_2/build_environment_2_1/readme.md +19 -0
- gitlabcis/recommendations/build_pipelines_2/build_environment_2_1/secure_build_env_webhooks.yml +43 -0
- gitlabcis/recommendations/build_pipelines_2/build_environment_2_1/single_responsibility_pipeline.yml +58 -0
- gitlabcis/recommendations/build_pipelines_2/build_environment_2_1/vuln_scanning.yml +64 -0
- gitlabcis/recommendations/build_pipelines_2/build_worker_2_2/build_worker_vuln_scanning.yml +58 -0
- gitlabcis/recommendations/build_pipelines_2/build_worker_2_2/monitor_worker_resource_consumption.yml +59 -0
- gitlabcis/recommendations/build_pipelines_2/build_worker_2_2/pass_worker_envs_and_commands.yml +48 -0
- gitlabcis/recommendations/build_pipelines_2/build_worker_2_2/readme.md +16 -0
- gitlabcis/recommendations/build_pipelines_2/build_worker_2_2/restrict_worker_connectivity.yml +61 -0
- gitlabcis/recommendations/build_pipelines_2/build_worker_2_2/segregate_worker_duties.yml +78 -0
- gitlabcis/recommendations/build_pipelines_2/build_worker_2_2/single_use_workers.yml +47 -0
- gitlabcis/recommendations/build_pipelines_2/build_worker_2_2/store_worker_config.yml +62 -0
- gitlabcis/recommendations/build_pipelines_2/build_worker_2_2/worker_runtime_security.yml +37 -0
- gitlabcis/recommendations/build_pipelines_2/pipeline_instructions_2_3/build_stage_io.yml +49 -0
- gitlabcis/recommendations/build_pipelines_2/pipeline_instructions_2_3/build_steps_as_code.yml +42 -0
- gitlabcis/recommendations/build_pipelines_2/pipeline_instructions_2_3/limit_pipeline_triggers.yml +76 -0
- gitlabcis/recommendations/build_pipelines_2/pipeline_instructions_2_3/pipeline_misconfiguration_scanning.yml +48 -0
- gitlabcis/recommendations/build_pipelines_2/pipeline_instructions_2_3/pipeline_secret_scanning.yml +56 -0
- gitlabcis/recommendations/build_pipelines_2/pipeline_instructions_2_3/pipeline_vuln_scanning.yml +44 -0
- gitlabcis/recommendations/build_pipelines_2/pipeline_instructions_2_3/readme.md +16 -0
- gitlabcis/recommendations/build_pipelines_2/pipeline_instructions_2_3/secure_pipeline_output.yml +52 -0
- gitlabcis/recommendations/build_pipelines_2/pipeline_instructions_2_3/track_pipeline_files.yml +48 -0
- gitlabcis/recommendations/build_pipelines_2/pipeline_integrity_2_4/create_reproducible_artifacts.yml +52 -0
- gitlabcis/recommendations/build_pipelines_2/pipeline_integrity_2_4/lock_dependencies.yml +59 -0
- gitlabcis/recommendations/build_pipelines_2/pipeline_integrity_2_4/pipeline_produces_sbom.yml +81 -0
- gitlabcis/recommendations/build_pipelines_2/pipeline_integrity_2_4/pipeline_signs_sbom.yml +38 -0
- gitlabcis/recommendations/build_pipelines_2/pipeline_integrity_2_4/readme.md +14 -0
- gitlabcis/recommendations/build_pipelines_2/pipeline_integrity_2_4/sign_artifacts.yml +35 -0
- gitlabcis/recommendations/build_pipelines_2/pipeline_integrity_2_4/validate_dependencies.yml +63 -0
- gitlabcis/recommendations/build_pipelines_2/readme.md +12 -0
- gitlabcis/recommendations/dependencies_3/readme.md +10 -0
- gitlabcis/recommendations/dependencies_3/third_party_packages_3_1/define_package_managers.yml +84 -0
- gitlabcis/recommendations/dependencies_3/third_party_packages_3_1/dependency_sbom.yml +84 -0
- gitlabcis/recommendations/dependencies_3/third_party_packages_3_1/monitor_dependencies.yml +61 -0
- gitlabcis/recommendations/dependencies_3/third_party_packages_3_1/packages_over_60_days_old.yml +95 -0
- gitlabcis/recommendations/dependencies_3/third_party_packages_3_1/pin_dependency_version.yml +48 -0
- gitlabcis/recommendations/dependencies_3/third_party_packages_3_1/readme.md +14 -0
- gitlabcis/recommendations/dependencies_3/third_party_packages_3_1/third_party_sbom_required.yml +70 -0
- gitlabcis/recommendations/dependencies_3/third_party_packages_3_1/verify_artifacts.yml +45 -0
- gitlabcis/recommendations/dependencies_3/third_party_packages_3_1/verify_signed_metadata.yml +41 -0
- gitlabcis/recommendations/dependencies_3/validate_packages_3_2/org_wide_dependency_policy.yml +47 -0
- gitlabcis/recommendations/dependencies_3/validate_packages_3_2/package_license_scanning.yml +47 -0
- gitlabcis/recommendations/dependencies_3/validate_packages_3_2/package_ownership_change.yml +42 -0
- gitlabcis/recommendations/dependencies_3/validate_packages_3_2/package_vuln_scanning.yml +62 -0
- gitlabcis/recommendations/dependencies_3/validate_packages_3_2/readme.md +10 -0
- gitlabcis/recommendations/deployment_5/deployment_configuration_5_1/audit_deployment_config.yml +46 -0
- gitlabcis/recommendations/deployment_5/deployment_configuration_5_1/limit_deployment_config_access.yml +51 -0
- gitlabcis/recommendations/deployment_5/deployment_configuration_5_1/pin_deployment_config_manifests.yml +59 -0
- gitlabcis/recommendations/deployment_5/deployment_configuration_5_1/readme.md +13 -0
- gitlabcis/recommendations/deployment_5/deployment_configuration_5_1/scan_iac.yml +72 -0
- gitlabcis/recommendations/deployment_5/deployment_configuration_5_1/secret_scan_deployment_config.yml +45 -0
- gitlabcis/recommendations/deployment_5/deployment_configuration_5_1/separate_deployment_config.yml +50 -0
- gitlabcis/recommendations/deployment_5/deployment_configuration_5_1/verify_deployment_config.yml +49 -0
- gitlabcis/recommendations/deployment_5/deployment_environment_5_2/automate_deployment.yml +47 -0
- gitlabcis/recommendations/deployment_5/deployment_environment_5_2/disable_default_passwords.yml +63 -0
- gitlabcis/recommendations/deployment_5/deployment_environment_5_2/limit_prod_access.yml +45 -0
- gitlabcis/recommendations/deployment_5/deployment_environment_5_2/readme.md +12 -0
- gitlabcis/recommendations/deployment_5/deployment_environment_5_2/reproducible_deployment.yml +50 -0
- gitlabcis/recommendations/deployment_5/readme.md +10 -0
- gitlabcis/recommendations/readme.md +24 -0
- gitlabcis/recommendations/source_code_1/code_changes_1_1/audit_branch_protections.yml +56 -0
- gitlabcis/recommendations/source_code_1/code_changes_1_1/auto_risk_scan_merges.yml +62 -0
- gitlabcis/recommendations/source_code_1/code_changes_1_1/branch_protections_for_admins.yml +60 -0
- gitlabcis/recommendations/source_code_1/code_changes_1_1/branches_updated_before_merging.yml +56 -0
- gitlabcis/recommendations/source_code_1/code_changes_1_1/checks_pass_before_merging.yml +57 -0
- gitlabcis/recommendations/source_code_1/code_changes_1_1/code_approval_dismissals.yml +62 -0
- gitlabcis/recommendations/source_code_1/code_changes_1_1/code_approvals.yml +65 -0
- gitlabcis/recommendations/source_code_1/code_changes_1_1/code_changes_require_code_owners.yml +68 -0
- gitlabcis/recommendations/source_code_1/code_changes_1_1/code_dismissal_restrictions.yml +69 -0
- gitlabcis/recommendations/source_code_1/code_changes_1_1/code_owners.yml +61 -0
- gitlabcis/recommendations/source_code_1/code_changes_1_1/code_tracing.yml +52 -0
- gitlabcis/recommendations/source_code_1/code_changes_1_1/comments_resolved_before_merging.yml +59 -0
- gitlabcis/recommendations/source_code_1/code_changes_1_1/commits_must_be_signed_before_merging.yml +63 -0
- gitlabcis/recommendations/source_code_1/code_changes_1_1/default_branch_protected.yml +85 -0
- gitlabcis/recommendations/source_code_1/code_changes_1_1/deny_branch_deletions.yml +76 -0
- gitlabcis/recommendations/source_code_1/code_changes_1_1/ensure_force_push_is_denied.yml +59 -0
- gitlabcis/recommendations/source_code_1/code_changes_1_1/linear_history_required.yml +56 -0
- gitlabcis/recommendations/source_code_1/code_changes_1_1/merging_restrictions.yml +65 -0
- gitlabcis/recommendations/source_code_1/code_changes_1_1/readme.md +26 -0
- gitlabcis/recommendations/source_code_1/code_changes_1_1/stale_branch_reviews.yml +72 -0
- gitlabcis/recommendations/source_code_1/code_changes_1_1/version_control.yml +45 -0
- gitlabcis/recommendations/source_code_1/code_risks_1_5/dast_api_scanning.yml +50 -0
- gitlabcis/recommendations/source_code_1/code_risks_1_5/dast_web_scanning.yml +51 -0
- gitlabcis/recommendations/source_code_1/code_risks_1_5/dependency_scanning.yml +84 -0
- gitlabcis/recommendations/source_code_1/code_risks_1_5/enable_secret_detection.yml +45 -0
- gitlabcis/recommendations/source_code_1/code_risks_1_5/license_scanning.yml +47 -0
- gitlabcis/recommendations/source_code_1/code_risks_1_5/readme.md +14 -0
- gitlabcis/recommendations/source_code_1/code_risks_1_5/secure_iac_instructions.yml +81 -0
- gitlabcis/recommendations/source_code_1/code_risks_1_5/secure_pipeline_instructions.yml +62 -0
- gitlabcis/recommendations/source_code_1/code_risks_1_5/vulnerability_scanning.yml +48 -0
- gitlabcis/recommendations/source_code_1/contribution_access_1_3/domain_verification.yml +65 -0
- gitlabcis/recommendations/source_code_1/contribution_access_1_3/ensure_2_admins_per_repo.yml +56 -0
- gitlabcis/recommendations/source_code_1/contribution_access_1_3/limit_top_level_group_creation.yml +61 -0
- gitlabcis/recommendations/source_code_1/contribution_access_1_3/limit_user_registration_domain.yml +58 -0
- gitlabcis/recommendations/source_code_1/contribution_access_1_3/minimum_number_of_admins.yml +56 -0
- gitlabcis/recommendations/source_code_1/contribution_access_1_3/org_provided_ssh_certs.yml +70 -0
- gitlabcis/recommendations/source_code_1/contribution_access_1_3/readme.md +21 -0
- gitlabcis/recommendations/source_code_1/contribution_access_1_3/require_mfa_at_org_level.yml +89 -0
- gitlabcis/recommendations/source_code_1/contribution_access_1_3/require_mfa_for_contributors.yml +76 -0
- gitlabcis/recommendations/source_code_1/contribution_access_1_3/restrict_ip_addresses.yml +84 -0
- gitlabcis/recommendations/source_code_1/contribution_access_1_3/review_and_remove_inactive_users.yml +62 -0
- gitlabcis/recommendations/source_code_1/contribution_access_1_3/scm_notification_restriction.yml +46 -0
- gitlabcis/recommendations/source_code_1/contribution_access_1_3/strict_permissions_for_repo.yml +62 -0
- gitlabcis/recommendations/source_code_1/contribution_access_1_3/track_code_anomalies.yml +43 -0
- gitlabcis/recommendations/source_code_1/readme.md +13 -0
- gitlabcis/recommendations/source_code_1/repository_management_1_2/limit_issue_deletions.yml +57 -0
- gitlabcis/recommendations/source_code_1/repository_management_1_2/limit_repo_creations.yml +64 -0
- gitlabcis/recommendations/source_code_1/repository_management_1_2/limit_repo_deletions.yml +57 -0
- gitlabcis/recommendations/source_code_1/repository_management_1_2/public_repos_have_security_file.yml +59 -0
- gitlabcis/recommendations/source_code_1/repository_management_1_2/readme.md +15 -0
- gitlabcis/recommendations/source_code_1/repository_management_1_2/review_and_archive_stale_repos.yml +65 -0
- gitlabcis/recommendations/source_code_1/repository_management_1_2/track_forks.yml +74 -0
- gitlabcis/recommendations/source_code_1/repository_management_1_2/track_project_visibility_status.yml +74 -0
- gitlabcis/recommendations/source_code_1/third_party_1_4/README.md +12 -0
- gitlabcis/recommendations/source_code_1/third_party_1_4/admin_approval_for_app_installs.yml +83 -0
- gitlabcis/recommendations/source_code_1/third_party_1_4/least_privilge_app_permissions.yml +103 -0
- gitlabcis/recommendations/source_code_1/third_party_1_4/secure_webhooks.yml +73 -0
- gitlabcis/recommendations/source_code_1/third_party_1_4/stale_app_reviews.yml +66 -0
- gitlabcis/recommendations/template.yml +30 -0
- gitlabcis/tests/__init__.py +0 -0
- gitlabcis/tests/input/__init__.py +0 -0
- gitlabcis/tests/input/conftest.py +29 -0
- gitlabcis/tests/input/no_input_test.py +82 -0
- gitlabcis/tests/input/switch_test.py +19 -0
- gitlabcis/tests/input/version_test.py +7 -0
- gitlabcis/tests/unit/__init__.py +0 -0
- gitlabcis/tests/unit/benchmarks/artifacts_4/access_to_artifacts_4_2_test.py +131 -0
- gitlabcis/tests/unit/benchmarks/artifacts_4/origin_traceability_4_4_test.py +15 -0
- gitlabcis/tests/unit/benchmarks/artifacts_4/package_registries_4_3_test.py +102 -0
- gitlabcis/tests/unit/benchmarks/artifacts_4/verification_4_1_test.py +78 -0
- gitlabcis/tests/unit/benchmarks/build_pipelines_2/build_environment_2_1_test.py +239 -0
- gitlabcis/tests/unit/benchmarks/build_pipelines_2/build_worker_2_2_test.py +105 -0
- gitlabcis/tests/unit/benchmarks/build_pipelines_2/pipeline_instructions_2_3_test.py +340 -0
- gitlabcis/tests/unit/benchmarks/build_pipelines_2/pipeline_integrity_2_4_test.py +115 -0
- gitlabcis/tests/unit/benchmarks/conftest.py +47 -0
- gitlabcis/tests/unit/benchmarks/dependencies_3/third_party_packages_3_1_test.py +135 -0
- gitlabcis/tests/unit/benchmarks/dependencies_3/validate_packages_3_2_test.py +171 -0
- gitlabcis/tests/unit/benchmarks/deployment_5/deployment_configuration_5_1_test.py +140 -0
- gitlabcis/tests/unit/benchmarks/deployment_5/deployment_environment_5_2_test.py +60 -0
- gitlabcis/tests/unit/benchmarks/function_test.py +24 -0
- gitlabcis/tests/unit/benchmarks/source_code_1/code_changes_1_1_test.py +565 -0
- gitlabcis/tests/unit/benchmarks/source_code_1/code_risks_1_5_test.py +419 -0
- gitlabcis/tests/unit/benchmarks/source_code_1/contribution_access_1_3_test.py +265 -0
- gitlabcis/tests/unit/benchmarks/source_code_1/repository_management_1_2_test.py +142 -0
- gitlabcis/tests/unit/benchmarks/source_code_1/third_party_1_4_test.py +119 -0
- gitlabcis/tests/unit/conftest.py +94 -0
- gitlabcis/tests/unit/log/log_test.py +23 -0
- gitlabcis/tests/unit/utils/argfilters_test.py +9 -0
- gitlabcis/tests/unit/utils/ci_test.py +156 -0
- gitlabcis/tests/unit/utils/output_test.py +95 -0
- gitlabcis/tests/unit/utils/utils_general_test.py +149 -0
- gitlabcis/tests/unit/utils/version_test.py +11 -0
- gitlabcis/tests/unit/yaml/bad_file_test.py +15 -0
- gitlabcis/tests/unit/yaml/recommendation_test.py +123 -0
- gitlabcis/utils/__init__.py +146 -0
- gitlabcis/utils/ci.py +132 -0
- gitlabcis-1.3.2.dist-info/LICENSE +21 -0
- gitlabcis-1.3.2.dist-info/METADATA +241 -0
- gitlabcis-1.3.2.dist-info/RECORD +218 -0
- gitlabcis-1.3.2.dist-info/WHEEL +5 -0
- gitlabcis-1.3.2.dist-info/entry_points.txt +2 -0
- gitlabcis-1.3.2.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
# -------------------------------------------------------------------------
|
|
2
|
+
|
|
3
|
+
def review_and_remove_inactive_users(glEntity, glObject, **kwargs):
|
|
4
|
+
"""
|
|
5
|
+
id: 1.3.1
|
|
6
|
+
title: Ensure inactive users are reviewed and removed periodically
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from gitlab.exceptions import GitlabGetError, GitlabHttpError
|
|
10
|
+
from gitlab.exceptions import GitlabAuthenticationError
|
|
11
|
+
from gitlab.exceptions import GitlabListError
|
|
12
|
+
|
|
13
|
+
from dateutil.relativedelta import relativedelta
|
|
14
|
+
from datetime import datetime, timezone
|
|
15
|
+
|
|
16
|
+
try:
|
|
17
|
+
ninetyDaysAgo = datetime.now(timezone.utc) - relativedelta(days=90)
|
|
18
|
+
|
|
19
|
+
users = glObject.users.list(per_page=100, iterator=True)
|
|
20
|
+
|
|
21
|
+
for user in users:
|
|
22
|
+
|
|
23
|
+
# a regular PAT is not going to return this value:
|
|
24
|
+
try:
|
|
25
|
+
if user.last_activity_on is None:
|
|
26
|
+
continue
|
|
27
|
+
except AttributeError:
|
|
28
|
+
return {None: 'Insufficient permissions'}
|
|
29
|
+
|
|
30
|
+
if datetime.strptime(
|
|
31
|
+
user.last_activity_on,
|
|
32
|
+
'%Y-%m-%d'
|
|
33
|
+
).replace(tzinfo=timezone.utc) > ninetyDaysAgo:
|
|
34
|
+
return {
|
|
35
|
+
False: 'User found with last activity longer than 90 days'}
|
|
36
|
+
|
|
37
|
+
return {True: 'No users found with activity longer than 90 days'}
|
|
38
|
+
|
|
39
|
+
except (GitlabHttpError, GitlabGetError, GitlabAuthenticationError,
|
|
40
|
+
GitlabListError) as e:
|
|
41
|
+
if e.response_code in [401, 403]:
|
|
42
|
+
return {None: 'Insufficient permissions'}
|
|
43
|
+
|
|
44
|
+
# -------------------------------------------------------------------------
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def limit_top_level_group_creation(glEntity, glObject, **kwargs):
|
|
48
|
+
"""
|
|
49
|
+
id: 1.3.2
|
|
50
|
+
title: Ensure top-level group creation is limited to specific members
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
from gitlab.exceptions import GitlabGetError, GitlabHttpError
|
|
54
|
+
from gitlab.exceptions import GitlabAuthenticationError
|
|
55
|
+
|
|
56
|
+
try:
|
|
57
|
+
if glObject.settings.get().can_create_group is False:
|
|
58
|
+
return {True: 'Top-level group creation is limited'}
|
|
59
|
+
|
|
60
|
+
return {False: 'Top-level group creation is not limited'}
|
|
61
|
+
|
|
62
|
+
except (GitlabHttpError, GitlabGetError, GitlabAuthenticationError) as e:
|
|
63
|
+
if e.response_code in [401, 403, 404]:
|
|
64
|
+
return {None: 'Insufficient permissions'}
|
|
65
|
+
|
|
66
|
+
# -------------------------------------------------------------------------
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def minimum_number_of_admins(glEntity, glObject, **kwargs):
|
|
70
|
+
"""
|
|
71
|
+
id: 1.3.3
|
|
72
|
+
title: Ensure minimum number of administrators are set for the
|
|
73
|
+
organization
|
|
74
|
+
"""
|
|
75
|
+
|
|
76
|
+
from gitlab.exceptions import GitlabGetError, GitlabHttpError
|
|
77
|
+
from gitlab.exceptions import GitlabAuthenticationError
|
|
78
|
+
|
|
79
|
+
try:
|
|
80
|
+
members = glEntity.members_all.list(get_all=True)
|
|
81
|
+
|
|
82
|
+
totalMembers = len(members)
|
|
83
|
+
|
|
84
|
+
if totalMembers == 1:
|
|
85
|
+
return {None: 'Only 1 member found'}
|
|
86
|
+
|
|
87
|
+
# Access levels:
|
|
88
|
+
# No access 0
|
|
89
|
+
# Minimal access 5
|
|
90
|
+
# Guest 10
|
|
91
|
+
# Reporter 20
|
|
92
|
+
# Developer 30
|
|
93
|
+
# Maintainer 40
|
|
94
|
+
# Owner 50
|
|
95
|
+
|
|
96
|
+
ownersOrMaintainers = []
|
|
97
|
+
for member in members:
|
|
98
|
+
if member.access_level >= 40:
|
|
99
|
+
ownersOrMaintainers.append(member)
|
|
100
|
+
|
|
101
|
+
if len(ownersOrMaintainers) < totalMembers:
|
|
102
|
+
return {True: 'Less owners/maintainers than members set'}
|
|
103
|
+
|
|
104
|
+
return {False: 'Access levels not restrictive for members'}
|
|
105
|
+
|
|
106
|
+
except (GitlabHttpError, GitlabGetError, GitlabAuthenticationError) as e:
|
|
107
|
+
if e.response_code in [401, 403, 404]:
|
|
108
|
+
return {None: 'Insufficient permissions'}
|
|
109
|
+
|
|
110
|
+
# -------------------------------------------------------------------------
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def require_mfa_for_contributors(glEntity, glObject, **kwargs):
|
|
114
|
+
"""
|
|
115
|
+
id: 1.3.4
|
|
116
|
+
title: Ensure Multi-Factor Authentication (MFA) is required for
|
|
117
|
+
contributors of new code
|
|
118
|
+
"""
|
|
119
|
+
|
|
120
|
+
from gitlab.exceptions import GitlabGetError, GitlabHttpError
|
|
121
|
+
from gitlab.exceptions import GitlabAuthenticationError
|
|
122
|
+
|
|
123
|
+
try:
|
|
124
|
+
_settings = glObject.settings.get()
|
|
125
|
+
|
|
126
|
+
if _settings.require_two_factor_authentication is True:
|
|
127
|
+
return {True: 'Two Factor Authentication is required'}
|
|
128
|
+
|
|
129
|
+
return {False: 'Two Factor Authentication is not required'}
|
|
130
|
+
|
|
131
|
+
except (GitlabHttpError, GitlabGetError, GitlabAuthenticationError) as e:
|
|
132
|
+
if e.response_code in [401, 403, 404]:
|
|
133
|
+
return {None: 'Insufficient permissions'}
|
|
134
|
+
|
|
135
|
+
# -------------------------------------------------------------------------
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def require_mfa_at_org_level(glEntity, glObject, **kwargs):
|
|
139
|
+
"""
|
|
140
|
+
id: 1.3.5
|
|
141
|
+
title: Ensure the organization is requiring members to use
|
|
142
|
+
Multi-Factor Authentication (MFA)
|
|
143
|
+
"""
|
|
144
|
+
|
|
145
|
+
from gitlab.exceptions import GitlabGetError, GitlabHttpError
|
|
146
|
+
from gitlab.exceptions import GitlabAuthenticationError
|
|
147
|
+
|
|
148
|
+
try:
|
|
149
|
+
_settings = glObject.settings.get()
|
|
150
|
+
|
|
151
|
+
if _settings.require_two_factor_authentication is True:
|
|
152
|
+
return {True: 'Two Factor Authentication is required'}
|
|
153
|
+
|
|
154
|
+
if _settings.two_factor_grace_period != 0:
|
|
155
|
+
return {True: 'Grace period is set for Two Factor Authentication'}
|
|
156
|
+
|
|
157
|
+
return {False: 'Two Factor Authentication is not required'}
|
|
158
|
+
|
|
159
|
+
except (GitlabHttpError, GitlabGetError, GitlabAuthenticationError) as e:
|
|
160
|
+
if e.response_code in [401, 403, 404]:
|
|
161
|
+
return {None: 'Insufficient permissions'}
|
|
162
|
+
|
|
163
|
+
# -------------------------------------------------------------------------
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def limit_user_registration_domain(glEntity, glObject, **kwargs):
|
|
167
|
+
"""
|
|
168
|
+
id: 1.3.6
|
|
169
|
+
title: Ensure new members are required to be invited using
|
|
170
|
+
company-approved email
|
|
171
|
+
"""
|
|
172
|
+
|
|
173
|
+
# We cannot automatically answer this check, therefore we SKIP:
|
|
174
|
+
return {None: 'This check requires validation'}
|
|
175
|
+
|
|
176
|
+
# -------------------------------------------------------------------------
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def ensure_2_admins_per_repo(glEntity, glObject, **kwargs):
|
|
180
|
+
"""
|
|
181
|
+
id: 1.3.7
|
|
182
|
+
title: Ensure two administrators are set for each repository
|
|
183
|
+
"""
|
|
184
|
+
|
|
185
|
+
from gitlab.exceptions import GitlabGetError, GitlabHttpError
|
|
186
|
+
from gitlab.exceptions import GitlabAuthenticationError
|
|
187
|
+
|
|
188
|
+
try:
|
|
189
|
+
owners = 0
|
|
190
|
+
members = glEntity.members_all.list(get_all=True)
|
|
191
|
+
|
|
192
|
+
for member in members:
|
|
193
|
+
|
|
194
|
+
if member.access_level == 50:
|
|
195
|
+
owners += 1
|
|
196
|
+
|
|
197
|
+
if owners == 2:
|
|
198
|
+
return {True: 'Two repository owners found'}
|
|
199
|
+
|
|
200
|
+
return {
|
|
201
|
+
True: 'No repository owners found'
|
|
202
|
+
if owners == 0
|
|
203
|
+
else f'Only found: {owners} owners'}
|
|
204
|
+
|
|
205
|
+
except (GitlabHttpError, GitlabGetError, GitlabAuthenticationError) as e:
|
|
206
|
+
if e.response_code in [401, 403]:
|
|
207
|
+
return {None: 'Insufficient permissions'}
|
|
208
|
+
|
|
209
|
+
# this throws an attr error if accessed anonymously (pytest no auth)
|
|
210
|
+
except AttributeError:
|
|
211
|
+
return {None: 'Insufficient permissions'}
|
|
212
|
+
|
|
213
|
+
# -------------------------------------------------------------------------
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
def strict_permissions_for_repo(glEntity, glObject, **kwargs):
|
|
217
|
+
"""
|
|
218
|
+
id: 1.3.8
|
|
219
|
+
title: Ensure strict base permissions are set for repositories
|
|
220
|
+
"""
|
|
221
|
+
|
|
222
|
+
from gitlab.exceptions import GitlabGetError, GitlabHttpError
|
|
223
|
+
from gitlab.exceptions import GitlabAuthenticationError
|
|
224
|
+
from gitlab.exceptions import GitlabListError
|
|
225
|
+
|
|
226
|
+
try:
|
|
227
|
+
members = glEntity.members_all.list(get_all=True)
|
|
228
|
+
|
|
229
|
+
totalMembers = len(members)
|
|
230
|
+
|
|
231
|
+
if totalMembers == 1:
|
|
232
|
+
return {None: 'Only 1 member found'}
|
|
233
|
+
|
|
234
|
+
# Access levels:
|
|
235
|
+
# No access 0
|
|
236
|
+
# Minimal access 5
|
|
237
|
+
# Guest 10
|
|
238
|
+
# Reporter 20
|
|
239
|
+
# Developer 30
|
|
240
|
+
# Maintainer 40
|
|
241
|
+
# Owner 50
|
|
242
|
+
|
|
243
|
+
ownersOrMaintainers = []
|
|
244
|
+
for member in members:
|
|
245
|
+
if member.access_level >= 40:
|
|
246
|
+
ownersOrMaintainers.append(member)
|
|
247
|
+
|
|
248
|
+
if len(ownersOrMaintainers) < totalMembers:
|
|
249
|
+
return {True: 'Less owners/maintainers than members set'}
|
|
250
|
+
|
|
251
|
+
return {False: 'Access levels not restrictive for members'}
|
|
252
|
+
|
|
253
|
+
except (GitlabHttpError, GitlabGetError, GitlabAuthenticationError,
|
|
254
|
+
GitlabListError) as e:
|
|
255
|
+
if e.response_code in [401, 403]:
|
|
256
|
+
return {None: 'Insufficient permissions'}
|
|
257
|
+
|
|
258
|
+
# -------------------------------------------------------------------------
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
def domain_verification(glEntity, glObject, **kwargs):
|
|
262
|
+
"""
|
|
263
|
+
id: 1.3.9
|
|
264
|
+
title: Ensure an organization's identity is confirmed with a “Verified”
|
|
265
|
+
badge
|
|
266
|
+
"""
|
|
267
|
+
|
|
268
|
+
return {None: 'This check requires validation'}
|
|
269
|
+
|
|
270
|
+
# -------------------------------------------------------------------------
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
def scm_notification_restriction(glEntity, glObject, **kwargs):
|
|
274
|
+
"""
|
|
275
|
+
id: 1.3.10
|
|
276
|
+
title: Ensure Source Code Management (SCM) email notifications are
|
|
277
|
+
restricted to verified domains
|
|
278
|
+
"""
|
|
279
|
+
|
|
280
|
+
return {None: 'This check requires validation'}
|
|
281
|
+
|
|
282
|
+
# -------------------------------------------------------------------------
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
def org_provided_ssh_certs(glEntity, glObject, **kwargs):
|
|
286
|
+
"""
|
|
287
|
+
id: 1.3.11
|
|
288
|
+
title: Ensure an organization provides SSH certificates
|
|
289
|
+
"""
|
|
290
|
+
|
|
291
|
+
from gitlab.exceptions import GitlabGetError, GitlabHttpError
|
|
292
|
+
from gitlab.exceptions import GitlabAuthenticationError
|
|
293
|
+
|
|
294
|
+
try:
|
|
295
|
+
keyRestrictions = [
|
|
296
|
+
'ed25519_key_restriction', 'ecdsa_key_restriction',
|
|
297
|
+
'dsa_key_restriction', 'rsa_key_restriction',
|
|
298
|
+
'ecdsa_sk_key_restriction', 'ed25519_sk_key_restriction'
|
|
299
|
+
]
|
|
300
|
+
|
|
301
|
+
settings = glObject.settings.get()
|
|
302
|
+
|
|
303
|
+
for restriction in keyRestrictions:
|
|
304
|
+
|
|
305
|
+
if getattr(settings, restriction) != 0:
|
|
306
|
+
return {True: f'{restriction} is enforced'}
|
|
307
|
+
|
|
308
|
+
return {False: 'No key restrictions set'}
|
|
309
|
+
|
|
310
|
+
except (GitlabHttpError, GitlabGetError, GitlabAuthenticationError) as e:
|
|
311
|
+
if e.response_code in [401, 403]:
|
|
312
|
+
return {None: 'Insufficient permissions'}
|
|
313
|
+
|
|
314
|
+
# -------------------------------------------------------------------------
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
def restrict_ip_addresses(glEntity, glObject, **kwargs):
|
|
318
|
+
"""
|
|
319
|
+
id: 1.3.12
|
|
320
|
+
title: Ensure Git access is limited based on IP addresses
|
|
321
|
+
"""
|
|
322
|
+
|
|
323
|
+
return {None: 'This check requires validation'}
|
|
324
|
+
|
|
325
|
+
# -------------------------------------------------------------------------
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
def track_code_anomalies(glEntity, glObject, **kwargs):
|
|
329
|
+
"""
|
|
330
|
+
id: 1.3.13
|
|
331
|
+
title: Ensure anomalous code behavior is tracked
|
|
332
|
+
"""
|
|
333
|
+
|
|
334
|
+
return {None: 'This check requires validation'}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
# -------------------------------------------------------------------------
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def public_repos_have_security_file(glEntity, glObject, **kwargs):
|
|
5
|
+
"""
|
|
6
|
+
id: 1.2.1
|
|
7
|
+
title: Ensure all public repositories contain a SECURITY.md file
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from gitlab.exceptions import (GitlabAuthenticationError, GitlabGetError,
|
|
11
|
+
GitlabHttpError)
|
|
12
|
+
|
|
13
|
+
try:
|
|
14
|
+
# SKIP private repos:
|
|
15
|
+
try:
|
|
16
|
+
if glEntity.visibility == 'private':
|
|
17
|
+
return {None: 'Project is private'}
|
|
18
|
+
except AttributeError:
|
|
19
|
+
return {None: 'Insufficient permissions'}
|
|
20
|
+
|
|
21
|
+
# PASS if the SECURITY.md file exists in the root dir of default
|
|
22
|
+
# branch
|
|
23
|
+
_rootFiles = glEntity.repository_tree(path='')
|
|
24
|
+
|
|
25
|
+
for _file in _rootFiles:
|
|
26
|
+
if _file.get('name').upper() == 'SECURITY.MD':
|
|
27
|
+
return {True: 'SECURITY.md file found'}
|
|
28
|
+
|
|
29
|
+
return {False: 'No SECURITY.md file found'}
|
|
30
|
+
|
|
31
|
+
except (GitlabHttpError, GitlabGetError, GitlabAuthenticationError) as e:
|
|
32
|
+
if e.response_code in [401, 403]:
|
|
33
|
+
return {None: 'Insufficient permissions'}
|
|
34
|
+
|
|
35
|
+
# -------------------------------------------------------------------------
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def limit_repo_creations(glEntity, glObject, **kwargs):
|
|
39
|
+
"""
|
|
40
|
+
id: 1.2.2
|
|
41
|
+
title: Ensure repository creation is limited to specific members
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
from gitlab.exceptions import (GitlabAuthenticationError, GitlabGetError,
|
|
45
|
+
GitlabHttpError)
|
|
46
|
+
|
|
47
|
+
try:
|
|
48
|
+
settings = glObject.settings.get()
|
|
49
|
+
|
|
50
|
+
if settings.signup_enabled is False:
|
|
51
|
+
return {True: 'Public signup is disabled'}
|
|
52
|
+
|
|
53
|
+
if settings.signup_enabled is True and \
|
|
54
|
+
settings.require_admin_approval_after_user_signup is True and \
|
|
55
|
+
settings.email_confirmation_setting == 'hard':
|
|
56
|
+
return {True: 'Requires approval after signup and email '
|
|
57
|
+
'confirmation setting is "hard"'}
|
|
58
|
+
|
|
59
|
+
return {False: 'Either public signup enabled, admin approval after '
|
|
60
|
+
'signup not set or email confirmation is set to '
|
|
61
|
+
'"hard"'}
|
|
62
|
+
|
|
63
|
+
except (GitlabHttpError, GitlabGetError, GitlabAuthenticationError) as e:
|
|
64
|
+
if e.response_code in [401, 403]:
|
|
65
|
+
return {None: 'Insufficient permissions'}
|
|
66
|
+
|
|
67
|
+
# -------------------------------------------------------------------------
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def limit_repo_deletions(glEntity, glObject, **kwargs):
|
|
71
|
+
"""
|
|
72
|
+
id: 1.2.3
|
|
73
|
+
title: Ensure repository deletion is limited to specific users
|
|
74
|
+
"""
|
|
75
|
+
|
|
76
|
+
# attempting to paginate over 1,000 users in a project which
|
|
77
|
+
# recived their membership due to nested-group permissions...
|
|
78
|
+
# results in a large wait-time for this function to run.
|
|
79
|
+
# roughly it take 1.5 minutes for it to complete all of /gitlab-com.
|
|
80
|
+
|
|
81
|
+
return {None: 'This check requires validation'}
|
|
82
|
+
|
|
83
|
+
# -------------------------------------------------------------------------
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def limit_issue_deletions(glEntity, glObject, **kwargs):
|
|
87
|
+
"""
|
|
88
|
+
id: 1.2.4
|
|
89
|
+
title: Ensure issue deletion is limited to specific users
|
|
90
|
+
"""
|
|
91
|
+
|
|
92
|
+
# attempting to paginate over 1,000 users in a project which
|
|
93
|
+
# recived their membership due to nested-group permissions...
|
|
94
|
+
# results in a large wait-time for this function to run.
|
|
95
|
+
# roughly it take 1.5 minutes for it to complete all of /gitlab-com.
|
|
96
|
+
|
|
97
|
+
return {None: 'This check requires validation'}
|
|
98
|
+
|
|
99
|
+
# -------------------------------------------------------------------------
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def track_forks(glEntity, glObject, **kwargs):
|
|
103
|
+
"""
|
|
104
|
+
id: 1.2.5
|
|
105
|
+
title: Ensure all copies (forks) of code are tracked and accounted for
|
|
106
|
+
"""
|
|
107
|
+
|
|
108
|
+
from gitlab.exceptions import (GitlabAuthenticationError, GitlabGetError,
|
|
109
|
+
GitlabHttpError, GitlabListError)
|
|
110
|
+
|
|
111
|
+
try:
|
|
112
|
+
_forksFound = glEntity.forks.list(get_all=False)
|
|
113
|
+
|
|
114
|
+
if not _forksFound:
|
|
115
|
+
return {True: 'No forks found'}
|
|
116
|
+
|
|
117
|
+
# we can't track and account for forks, so SKIP if forks found
|
|
118
|
+
return {None: 'Cannot track and account for forks'}
|
|
119
|
+
|
|
120
|
+
except (GitlabHttpError, GitlabGetError, GitlabAuthenticationError,
|
|
121
|
+
GitlabListError) as e:
|
|
122
|
+
if e.response_code in [403, 404]:
|
|
123
|
+
return {None: 'Insufficient permissions'}
|
|
124
|
+
|
|
125
|
+
# -------------------------------------------------------------------------
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def track_project_visibility_status(glEntity, glObject, **kwargs):
|
|
129
|
+
"""
|
|
130
|
+
id: 1.2.6
|
|
131
|
+
title: Ensure all code projects are tracked for changes in visibility
|
|
132
|
+
status
|
|
133
|
+
"""
|
|
134
|
+
|
|
135
|
+
# We cannot automatically answer this check, therefore we SKIP:
|
|
136
|
+
return {None: 'This check requires validation'}
|
|
137
|
+
|
|
138
|
+
# -------------------------------------------------------------------------
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def review_and_archive_stale_repos(glEntity, glObject, **kwargs):
|
|
142
|
+
"""
|
|
143
|
+
id: 1.2.7
|
|
144
|
+
title: Ensure inactive repositories are reviewed and archived
|
|
145
|
+
periodically
|
|
146
|
+
"""
|
|
147
|
+
|
|
148
|
+
from datetime import datetime, timezone
|
|
149
|
+
|
|
150
|
+
from dateutil.relativedelta import relativedelta
|
|
151
|
+
from gitlab.exceptions import (GitlabAuthenticationError, GitlabGetError,
|
|
152
|
+
GitlabHttpError)
|
|
153
|
+
|
|
154
|
+
try:
|
|
155
|
+
lastActivity = datetime.strptime(
|
|
156
|
+
glEntity.last_activity_at, '%Y-%m-%dT%H:%M:%S.%fZ'
|
|
157
|
+
).replace(tzinfo=timezone.utc)
|
|
158
|
+
|
|
159
|
+
sixMonthsAgo = datetime.now(timezone.utc) - relativedelta(months=6)
|
|
160
|
+
|
|
161
|
+
if lastActivity > sixMonthsAgo:
|
|
162
|
+
return {True: 'Repository is active'}
|
|
163
|
+
|
|
164
|
+
return {False: 'Repository is inactive'}
|
|
165
|
+
|
|
166
|
+
except (GitlabHttpError, GitlabGetError, GitlabAuthenticationError) as e:
|
|
167
|
+
if e.response_code in [401, 403]:
|
|
168
|
+
return {None: 'Insufficient permissions'}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# -------------------------------------------------------------------------
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def admin_approval_for_app_installs(glEntity, glObject, **kwargs):
|
|
5
|
+
"""
|
|
6
|
+
id: 1.4.1
|
|
7
|
+
title: Ensure administrator approval is required for every installed
|
|
8
|
+
application
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
return {True: 'You are compliant by default. Only maintainers and '
|
|
12
|
+
'owners can integrate with external applications'}
|
|
13
|
+
|
|
14
|
+
# -------------------------------------------------------------------------
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def stale_app_reviews(glEntity, glObject, **kwargs):
|
|
18
|
+
"""
|
|
19
|
+
id: 1.4.2
|
|
20
|
+
title: Ensure stale applications are reviewed and inactive ones are
|
|
21
|
+
removed
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
from gitlab.exceptions import (GitlabAuthenticationError, GitlabGetError,
|
|
25
|
+
GitlabHttpError)
|
|
26
|
+
from gql import Client, gql
|
|
27
|
+
from gql.transport.exceptions import (TransportAlreadyConnected,
|
|
28
|
+
TransportServerError)
|
|
29
|
+
from gql.transport.requests import RequestsHTTPTransport
|
|
30
|
+
from graphql import GraphQLError
|
|
31
|
+
|
|
32
|
+
try:
|
|
33
|
+
|
|
34
|
+
variables = {
|
|
35
|
+
'fullPath': glEntity.path_with_namespace
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
except (GitlabHttpError, GitlabGetError, GitlabAuthenticationError) as e:
|
|
39
|
+
if e.response_code in [401, 403]:
|
|
40
|
+
return {None: 'Insufficient permissions'}
|
|
41
|
+
|
|
42
|
+
client = Client(
|
|
43
|
+
transport=RequestsHTTPTransport(
|
|
44
|
+
url=kwargs.get('graphQLEndpoint'),
|
|
45
|
+
headers=kwargs.get('graphQLHeaders'),
|
|
46
|
+
use_json=True
|
|
47
|
+
),
|
|
48
|
+
fetch_schema_from_transport=True
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
query = gql('''
|
|
52
|
+
query GetSecurityScanners($fullPath: ID!) {
|
|
53
|
+
project(fullPath: $fullPath) {
|
|
54
|
+
securityScanners {
|
|
55
|
+
enabled
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
''')
|
|
60
|
+
|
|
61
|
+
try:
|
|
62
|
+
|
|
63
|
+
results = client.execute(query, variable_values=variables)
|
|
64
|
+
|
|
65
|
+
except (GraphQLError, TransportServerError, TransportAlreadyConnected):
|
|
66
|
+
return {None: 'Error: Issue with GraphQL Query'}
|
|
67
|
+
|
|
68
|
+
# pytest no auth:
|
|
69
|
+
except AttributeError:
|
|
70
|
+
return {None: 'Insufficient permissions'}
|
|
71
|
+
|
|
72
|
+
try:
|
|
73
|
+
# dependency scanning alerts when there are stale applications present:
|
|
74
|
+
if 'DEPENDENCY_SCANNING' in \
|
|
75
|
+
results['project']['securityScanners']['enabled']:
|
|
76
|
+
return {True: 'Dependency Scanning is enabled'}
|
|
77
|
+
|
|
78
|
+
else:
|
|
79
|
+
return {False: 'Dependency Scanning is not enabled'}
|
|
80
|
+
|
|
81
|
+
except KeyError:
|
|
82
|
+
return {False: 'Dependency Scanning is not enabled'}
|
|
83
|
+
|
|
84
|
+
# -------------------------------------------------------------------------
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def least_privilge_app_permissions(glEntity, glObject, **kwargs):
|
|
88
|
+
"""
|
|
89
|
+
id: 1.4.3
|
|
90
|
+
title: Ensure the access granted to each installed application is
|
|
91
|
+
limited to the least privilege needed
|
|
92
|
+
"""
|
|
93
|
+
|
|
94
|
+
from gitlab.exceptions import (GitlabAuthenticationError, GitlabGetError,
|
|
95
|
+
GitlabHttpError, GitlabListError)
|
|
96
|
+
|
|
97
|
+
try:
|
|
98
|
+
integrations = glEntity.integrations.list(get_all=False)
|
|
99
|
+
|
|
100
|
+
if len(integrations) == 0:
|
|
101
|
+
return {True: 'No integrations found'}
|
|
102
|
+
|
|
103
|
+
return {None: 'This check requires validation'}
|
|
104
|
+
|
|
105
|
+
except (GitlabHttpError, GitlabGetError, GitlabAuthenticationError,
|
|
106
|
+
GitlabListError) as e:
|
|
107
|
+
if e.response_code in [401, 403]:
|
|
108
|
+
return {None: 'Insufficient permissions'}
|
|
109
|
+
|
|
110
|
+
# -------------------------------------------------------------------------
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def secure_webhooks(glEntity, glObject, **kwargs):
|
|
114
|
+
"""
|
|
115
|
+
id: 1.4.4
|
|
116
|
+
title: Ensure only secured webhooks are used
|
|
117
|
+
"""
|
|
118
|
+
|
|
119
|
+
from gitlab.exceptions import (GitlabAuthenticationError, GitlabGetError,
|
|
120
|
+
GitlabHttpError, GitlabListError)
|
|
121
|
+
|
|
122
|
+
try:
|
|
123
|
+
webhooks = glEntity.hooks.list(get_all=True)
|
|
124
|
+
|
|
125
|
+
if len(webhooks) == 0:
|
|
126
|
+
return {None: 'No webhooks found'}
|
|
127
|
+
|
|
128
|
+
for hook in webhooks:
|
|
129
|
+
|
|
130
|
+
if hook.enable_ssl_verification is False or \
|
|
131
|
+
hook.url.startswith('http://'):
|
|
132
|
+
return {False: 'Insecure webhook found'}
|
|
133
|
+
|
|
134
|
+
return {True: 'All webhooks using HTTPS'}
|
|
135
|
+
|
|
136
|
+
except (GitlabHttpError, GitlabGetError, GitlabAuthenticationError,
|
|
137
|
+
GitlabListError) as e:
|
|
138
|
+
if e.response_code in [401, 403]:
|
|
139
|
+
return {None: 'Insufficient permissions'}
|
|
File without changes
|
gitlabcis/cli/log.py
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# -----------------------------------------------------------------------------
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
|
|
5
|
+
# -----------------------------------------------------------------------------
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class CustomLogFilter(logging.Filter):
|
|
9
|
+
|
|
10
|
+
# -------------------------------------------------------------------------
|
|
11
|
+
|
|
12
|
+
def __init__(self, token):
|
|
13
|
+
|
|
14
|
+
super().__init__()
|
|
15
|
+
self.token = token
|
|
16
|
+
|
|
17
|
+
# -------------------------------------------------------------------------
|
|
18
|
+
|
|
19
|
+
def filter(self, record):
|
|
20
|
+
|
|
21
|
+
# The connection is being discarded after the request is completed
|
|
22
|
+
# we want to suppress this as it affects the cosmetics of the progress
|
|
23
|
+
if ('Connection pool is full, discarding connection'
|
|
24
|
+
in record.getMessage()):
|
|
25
|
+
return False
|
|
26
|
+
|
|
27
|
+
# Suppress any logs containing the token
|
|
28
|
+
record.msg = record.getMessage().replace(self.token, '[REDACTED]')
|
|
29
|
+
|
|
30
|
+
return True
|