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,149 @@
|
|
|
1
|
+
# -----------------------------------------------------------------------------
|
|
2
|
+
|
|
3
|
+
from collections import namedtuple
|
|
4
|
+
from unittest.mock import Mock, mock_open, patch
|
|
5
|
+
|
|
6
|
+
import pytest
|
|
7
|
+
import yaml
|
|
8
|
+
|
|
9
|
+
from gitlabcis.utils import (countRecommendations, mapRecommendations,
|
|
10
|
+
readRecommendations, readYaml)
|
|
11
|
+
|
|
12
|
+
# -----------------------------------------------------------------------------
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def test_count_recommendations():
|
|
16
|
+
assert countRecommendations() == 123
|
|
17
|
+
|
|
18
|
+
# -----------------------------------------------------------------------------
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def test_read_recommendations():
|
|
22
|
+
# options:
|
|
23
|
+
ArgFilters = namedtuple(
|
|
24
|
+
'ArgFilters', ['profile', 'recommendation_ids', 'cis_controls',
|
|
25
|
+
'implementation_groups', 'skip_recommendation_ids'])
|
|
26
|
+
|
|
27
|
+
# controls:
|
|
28
|
+
control1 = {
|
|
29
|
+
'id': '1.1.1', 'profile': '1',
|
|
30
|
+
'cis_controls': [{'id': '2.4', 'implementation_groups': 'IG2'}]}
|
|
31
|
+
|
|
32
|
+
control2 = {
|
|
33
|
+
'id': '1.1.12', 'profile': '2',
|
|
34
|
+
'cis_controls': [{'id': '16.1', 'implementation_groups': 'IG3'}]}
|
|
35
|
+
|
|
36
|
+
# run:
|
|
37
|
+
@patch('gitlabcis.utils.Path')
|
|
38
|
+
@patch('gitlabcis.utils.readYaml')
|
|
39
|
+
def run_test(mock_read_yaml, mock_path, arg_filters=None,
|
|
40
|
+
expected_result=None, expect_exit=False):
|
|
41
|
+
mock_path.return_value.exists.return_value = True
|
|
42
|
+
mock_path.return_value.rglob.return_value = ['file1.yml', 'file2.yml']
|
|
43
|
+
mock_read_yaml.side_effect = [control1, control2]
|
|
44
|
+
|
|
45
|
+
if expect_exit:
|
|
46
|
+
mock_path.return_value.exists.return_value = False
|
|
47
|
+
with pytest.raises(SystemExit):
|
|
48
|
+
readRecommendations(arg_filters)
|
|
49
|
+
else:
|
|
50
|
+
result = readRecommendations(arg_filters)
|
|
51
|
+
assert result == expected_result
|
|
52
|
+
|
|
53
|
+
# Test no filters
|
|
54
|
+
run_test(expected_result=[control1, control2])
|
|
55
|
+
|
|
56
|
+
# Test profile filter
|
|
57
|
+
run_test(
|
|
58
|
+
arg_filters=ArgFilters(profile='1', recommendation_ids=None,
|
|
59
|
+
cis_controls=None, implementation_groups=None,
|
|
60
|
+
skip_recommendation_ids=None),
|
|
61
|
+
expected_result=[control1]
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
# Test recommendation_ids filter
|
|
65
|
+
run_test(
|
|
66
|
+
arg_filters=ArgFilters(profile=None, recommendation_ids=['1.1.12'],
|
|
67
|
+
cis_controls=None, implementation_groups=None,
|
|
68
|
+
skip_recommendation_ids=None),
|
|
69
|
+
expected_result=[control2]
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
# Test skip_recommendation_ids filter
|
|
73
|
+
run_test(
|
|
74
|
+
arg_filters=ArgFilters(profile=None, recommendation_ids=None,
|
|
75
|
+
cis_controls=None, implementation_groups=None,
|
|
76
|
+
skip_recommendation_ids=['1.1.12']),
|
|
77
|
+
expected_result=[control1]
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
# Test cis_controls filter
|
|
81
|
+
run_test(
|
|
82
|
+
arg_filters=ArgFilters(profile=None, recommendation_ids=None,
|
|
83
|
+
cis_controls=['16.1'],
|
|
84
|
+
implementation_groups=None,
|
|
85
|
+
skip_recommendation_ids=None),
|
|
86
|
+
expected_result=[control2]
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
# Test implementation_groups filter
|
|
90
|
+
run_test(
|
|
91
|
+
arg_filters=ArgFilters(profile=None, recommendation_ids=None,
|
|
92
|
+
cis_controls=None,
|
|
93
|
+
implementation_groups=['IG2'],
|
|
94
|
+
skip_recommendation_ids=None),
|
|
95
|
+
expected_result=[control1]
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
# Test directory not found
|
|
99
|
+
run_test(expect_exit=True)
|
|
100
|
+
|
|
101
|
+
# -----------------------------------------------------------------------------
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def test_read_yaml():
|
|
105
|
+
example_input = "key1: value1\nkey2: value2"
|
|
106
|
+
example_output = {'key1': 'value1', 'key2': 'value2'}
|
|
107
|
+
|
|
108
|
+
# Test successful read
|
|
109
|
+
with patch('builtins.open', new_callable=mock_open,
|
|
110
|
+
read_data=example_input):
|
|
111
|
+
result = readYaml('dummy_path.yml')
|
|
112
|
+
assert result == example_output
|
|
113
|
+
|
|
114
|
+
# Test file not found
|
|
115
|
+
with patch('builtins.open', side_effect=FileNotFoundError), \
|
|
116
|
+
patch('sys.exit') as mock_exit, \
|
|
117
|
+
pytest.raises(SystemExit):
|
|
118
|
+
readYaml('non_existent_file.yml')
|
|
119
|
+
mock_exit.assert_called_once_with(1)
|
|
120
|
+
|
|
121
|
+
# Test logging
|
|
122
|
+
with patch('builtins.open', new_callable=mock_open,
|
|
123
|
+
read_data=example_input), \
|
|
124
|
+
patch('logging.debug') as mock_debug:
|
|
125
|
+
readYaml('test_file.yml')
|
|
126
|
+
mock_debug.assert_called_once_with('Opening: test_file.yml')
|
|
127
|
+
|
|
128
|
+
# Test invalid YAML content
|
|
129
|
+
with patch('builtins.open', new_callable=mock_open,
|
|
130
|
+
read_data="invalid: yaml: content"), \
|
|
131
|
+
pytest.raises(yaml.YAMLError):
|
|
132
|
+
readYaml('invalid_yaml.yml')
|
|
133
|
+
|
|
134
|
+
# -----------------------------------------------------------------------------
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def test_map_recommendations():
|
|
138
|
+
functionList = [
|
|
139
|
+
Mock(__name__='func1'),
|
|
140
|
+
Mock(__name__='func2'),
|
|
141
|
+
Mock(__name__='func3')
|
|
142
|
+
]
|
|
143
|
+
|
|
144
|
+
recommendations = [{'name': 'func1'}, {'name': 'func2'},
|
|
145
|
+
{'name': 'func3'}]
|
|
146
|
+
|
|
147
|
+
assert len(
|
|
148
|
+
mapRecommendations(functionList, recommendations)
|
|
149
|
+
) == 3
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# -----------------------------------------------------------------------------
|
|
2
|
+
|
|
3
|
+
from gitlabcis import __version__
|
|
4
|
+
|
|
5
|
+
import re
|
|
6
|
+
|
|
7
|
+
# -----------------------------------------------------------------------------
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def test_gitlabcis_version():
|
|
11
|
+
assert re.match(r'^\d+\.\d+\.\d+$', __version__) is not None
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# -----------------------------------------------------------------------------
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
# -----------------------------------------------------------------------------
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def test_bad_file(capsys):
|
|
9
|
+
|
|
10
|
+
with pytest.raises(SystemExit) as execCtx:
|
|
11
|
+
from gitlabcis.utils import readYaml # noqa: F401
|
|
12
|
+
|
|
13
|
+
readYaml('non-existant.yml')
|
|
14
|
+
|
|
15
|
+
assert execCtx.value.code == 1
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# -----------------------------------------------------------------------------
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def test_valid_yaml_syntax(recommendations):
|
|
5
|
+
"""
|
|
6
|
+
This test ensures that all the required keys are present in the yaml
|
|
7
|
+
recommendation
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
# the required keys of the yaml file:
|
|
11
|
+
requiredKeys = [
|
|
12
|
+
'id', 'name', 'title', 'profile', 'category', 'sub_category',
|
|
13
|
+
'description', 'rationale', 'impact', 'audit', 'remediation',
|
|
14
|
+
'default_value', 'references', 'cis_controls', 'additional_info'
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
requiredKeys.sort()
|
|
18
|
+
|
|
19
|
+
for yamlName, yamlData in recommendations.items():
|
|
20
|
+
print(f' - Testing: {yamlData.get("id")} - {yamlName}') # noqa: E221,E501
|
|
21
|
+
|
|
22
|
+
yamlKeys = list(yamlData.keys())
|
|
23
|
+
yamlKeys.sort()
|
|
24
|
+
|
|
25
|
+
assert yamlKeys == requiredKeys
|
|
26
|
+
|
|
27
|
+
# -----------------------------------------------------------------------------
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def test_categories(recommendationDirs, recommendations):
|
|
31
|
+
"""
|
|
32
|
+
This test ensures that the category inside the yaml recommendation
|
|
33
|
+
matches those of the directories under /recommendations.
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
for yamlName, yamlData in recommendations.items():
|
|
37
|
+
print(f' - Testing: {yamlData.get("id")} - {yamlName}') # noqa: E221,E501
|
|
38
|
+
|
|
39
|
+
_expectedPath = (
|
|
40
|
+
f'{yamlData.get("category")}_{yamlData.get("id").split(".")[0]}'
|
|
41
|
+
)
|
|
42
|
+
assert _expectedPath in recommendationDirs
|
|
43
|
+
|
|
44
|
+
# -----------------------------------------------------------------------------
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def test_sub_categories(recommendationDirs, recommendations):
|
|
48
|
+
"""
|
|
49
|
+
This test ensures that the sub_category match those of the directories
|
|
50
|
+
under /recommendations.
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
for yamlName, yamlData in recommendations.items():
|
|
54
|
+
print(f' - Testing: {yamlData.get("id")} - {yamlName}') # noqa: E221,E501
|
|
55
|
+
|
|
56
|
+
_idSplit = yamlData.get('id').split('.')
|
|
57
|
+
_expectedPath = (
|
|
58
|
+
f'{yamlData.get("sub_category")}_{_idSplit[0]}_{_idSplit[1]}'
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
assert _expectedPath in recommendationDirs
|
|
62
|
+
|
|
63
|
+
# -----------------------------------------------------------------------------
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def test_duplicate_ids(recommendations):
|
|
67
|
+
"""
|
|
68
|
+
This test ensures that there are no duplicate IDs in the yaml files.
|
|
69
|
+
"""
|
|
70
|
+
|
|
71
|
+
_ids = []
|
|
72
|
+
|
|
73
|
+
for yamlName, yamlData in recommendations.items():
|
|
74
|
+
|
|
75
|
+
print(f' - Testing: {yamlData.get("id")} - {yamlName}') # noqa: E221,E501
|
|
76
|
+
|
|
77
|
+
if yamlData['id'] in _ids:
|
|
78
|
+
raise AssertionError(
|
|
79
|
+
f'Duplicate ID: {yamlData["id"]} found in file: {yamlName}'
|
|
80
|
+
)
|
|
81
|
+
_ids.append(yamlData['id'])
|
|
82
|
+
|
|
83
|
+
# -----------------------------------------------------------------------------
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def test_duplicate_names(recommendations):
|
|
87
|
+
"""
|
|
88
|
+
This test ensures that there are no duplicate names in the yaml files.
|
|
89
|
+
"""
|
|
90
|
+
|
|
91
|
+
_names = []
|
|
92
|
+
|
|
93
|
+
for yamlName, _yamlData in recommendations.items():
|
|
94
|
+
if yamlName in _names:
|
|
95
|
+
raise AssertionError(
|
|
96
|
+
f'Duplicate Name: {yamlName} found in {yamlName}')
|
|
97
|
+
_names.append(yamlName)
|
|
98
|
+
|
|
99
|
+
# -----------------------------------------------------------------------------
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def test_template_values(recommendations):
|
|
103
|
+
"""
|
|
104
|
+
This test ensures that there are no template values still in the file.
|
|
105
|
+
"""
|
|
106
|
+
|
|
107
|
+
for yamlName, yamlData in recommendations.items():
|
|
108
|
+
|
|
109
|
+
_checks = []
|
|
110
|
+
|
|
111
|
+
print(f' - Testing: {yamlData.get("id")} - {yamlName}') # noqa: E221,E501
|
|
112
|
+
|
|
113
|
+
for key, value in yamlData.items():
|
|
114
|
+
|
|
115
|
+
# for list items:
|
|
116
|
+
if key == 'references' and value:
|
|
117
|
+
_checks.append('example' not in [v for v in value])
|
|
118
|
+
|
|
119
|
+
# for single value items:
|
|
120
|
+
else:
|
|
121
|
+
_checks.append(value != 'example')
|
|
122
|
+
|
|
123
|
+
assert False not in _checks
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# -------------------------------------------------------------------------
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from sys import exit
|
|
6
|
+
|
|
7
|
+
import yaml
|
|
8
|
+
|
|
9
|
+
from . import ci # noqa: F401
|
|
10
|
+
|
|
11
|
+
# -----------------------------------------------------------------------------
|
|
12
|
+
# count recommendations:
|
|
13
|
+
# -----------------------------------------------------------------------------
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def countRecommendations():
|
|
17
|
+
return len(list(
|
|
18
|
+
Path(f'{Path(__file__).parent.parent}/recommendations').rglob('*.yml')
|
|
19
|
+
))
|
|
20
|
+
|
|
21
|
+
# -----------------------------------------------------------------------------
|
|
22
|
+
# Load the recommendations:
|
|
23
|
+
# -----------------------------------------------------------------------------
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def readRecommendations(argFilters=None):
|
|
27
|
+
|
|
28
|
+
_rDir = Path(f'{Path(__file__).parent.parent}/recommendations')
|
|
29
|
+
|
|
30
|
+
logging.debug(f'recommendations directory: {_rDir}')
|
|
31
|
+
|
|
32
|
+
if not _rDir.exists():
|
|
33
|
+
print(
|
|
34
|
+
f'Error: Recommendations directory {_rDir} was not found'
|
|
35
|
+
)
|
|
36
|
+
exit(1)
|
|
37
|
+
|
|
38
|
+
# -------------------------------------------------------------------------
|
|
39
|
+
# Gather all recommendations:
|
|
40
|
+
# -------------------------------------------------------------------------
|
|
41
|
+
|
|
42
|
+
recommendationFiles = list(_rDir.rglob('*.yml'))
|
|
43
|
+
|
|
44
|
+
if argFilters is None:
|
|
45
|
+
|
|
46
|
+
recommendations = [readYaml(r) for r in recommendationFiles]
|
|
47
|
+
logging.debug(f'Loaded: {len(recommendations)} recommendations')
|
|
48
|
+
|
|
49
|
+
return recommendations
|
|
50
|
+
|
|
51
|
+
# -------------------------------------------------------------------------
|
|
52
|
+
# Filter recommendations based on user input:
|
|
53
|
+
# -------------------------------------------------------------------------
|
|
54
|
+
|
|
55
|
+
logging.debug(f'Filtering with args: {argFilters}')
|
|
56
|
+
|
|
57
|
+
recommendations = []
|
|
58
|
+
|
|
59
|
+
for r in recommendationFiles:
|
|
60
|
+
|
|
61
|
+
yamlData = readYaml(r)
|
|
62
|
+
|
|
63
|
+
cisControls = yamlData.get('cis_controls', [])
|
|
64
|
+
|
|
65
|
+
# ---------------------------------------------------------------------
|
|
66
|
+
|
|
67
|
+
# if a profile was provided and it doesn't match in the recommendation:
|
|
68
|
+
if argFilters.profile:
|
|
69
|
+
if argFilters.profile != yamlData.get('profile'):
|
|
70
|
+
continue
|
|
71
|
+
|
|
72
|
+
# if a recommendation id was provided but it doesn't match:
|
|
73
|
+
if argFilters.recommendation_ids:
|
|
74
|
+
if yamlData.get('id') not in argFilters.recommendation_ids:
|
|
75
|
+
continue
|
|
76
|
+
|
|
77
|
+
# if a user wishes to skip certain recommendation id's:
|
|
78
|
+
if argFilters.skip_recommendation_ids:
|
|
79
|
+
if yamlData.get('id') in argFilters.skip_recommendation_ids:
|
|
80
|
+
continue
|
|
81
|
+
|
|
82
|
+
# ---------------------------------------------------------------------
|
|
83
|
+
# Iterate through the CIS Controls:
|
|
84
|
+
# ---------------------------------------------------------------------
|
|
85
|
+
|
|
86
|
+
# if a CIS Control ID was provided and it's not found:
|
|
87
|
+
if argFilters.cis_controls:
|
|
88
|
+
_cisIds = set([cis.get('id') for cis in cisControls])
|
|
89
|
+
|
|
90
|
+
if not set(argFilters.cis_controls).intersection(_cisIds):
|
|
91
|
+
continue
|
|
92
|
+
|
|
93
|
+
# if an implementation group was provided and it's not found:
|
|
94
|
+
if argFilters.implementation_groups:
|
|
95
|
+
|
|
96
|
+
if not set(argFilters.implementation_groups).intersection(
|
|
97
|
+
set([
|
|
98
|
+
control.get('implementation_groups')
|
|
99
|
+
for control in cisControls
|
|
100
|
+
])):
|
|
101
|
+
continue
|
|
102
|
+
|
|
103
|
+
# for everything else, append it, this allows a user to pass no
|
|
104
|
+
# args and they return all the recommendations...
|
|
105
|
+
recommendations.append(yamlData)
|
|
106
|
+
|
|
107
|
+
return recommendations
|
|
108
|
+
|
|
109
|
+
# -----------------------------------------------------------------------------
|
|
110
|
+
# Read a recommendation file:
|
|
111
|
+
# -----------------------------------------------------------------------------
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def readYaml(recommendation):
|
|
115
|
+
"""
|
|
116
|
+
Desc: This function takes a str path to a yaml file, reads it and
|
|
117
|
+
returns it.
|
|
118
|
+
"""
|
|
119
|
+
|
|
120
|
+
logging.debug(f'Opening: {recommendation}')
|
|
121
|
+
|
|
122
|
+
try:
|
|
123
|
+
with open(recommendation, 'r') as f:
|
|
124
|
+
return yaml.safe_load(f)
|
|
125
|
+
except FileNotFoundError:
|
|
126
|
+
print(f'Error: Failed to find recommendation: {recommendation}')
|
|
127
|
+
exit(1)
|
|
128
|
+
|
|
129
|
+
# -----------------------------------------------------------------------------
|
|
130
|
+
# Map functions to recommendations:
|
|
131
|
+
# -----------------------------------------------------------------------------
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def mapRecommendations(functionList, recommendationList):
|
|
135
|
+
"""
|
|
136
|
+
Desc: This function maps a function to its relevant recommendation
|
|
137
|
+
It accepts a list of functions, and a list of recommendation dicts.
|
|
138
|
+
"""
|
|
139
|
+
|
|
140
|
+
mappedFuncs = {func.__name__: func for func in functionList}
|
|
141
|
+
|
|
142
|
+
return {
|
|
143
|
+
mappedFuncs[recommendation['name']]: recommendation
|
|
144
|
+
for recommendation in recommendationList
|
|
145
|
+
if recommendation['name'] in mappedFuncs
|
|
146
|
+
}
|
gitlabcis/utils/ci.py
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# -------------------------------------------------------------------------
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def getConfig(glEntity, glObject, **kwargs):
|
|
5
|
+
"""
|
|
6
|
+
This function attempts to obtain the .gitlab-ci.yml file.
|
|
7
|
+
|
|
8
|
+
The filepath can be:
|
|
9
|
+
- Remote: e.g. https://example.com/.gitlab-ci.yml
|
|
10
|
+
- External: e.g. rel/path/.gitlab-ci.yml@my/project:refName
|
|
11
|
+
- Local: e.g. custom/local/repo/path/.gitlab-ci.yml
|
|
12
|
+
|
|
13
|
+
Ref: https://docs.gitlab.com/ee/ci/pipelines/settings.html#specify-a-custom-cicd-configuration-file # noqa: E501
|
|
14
|
+
|
|
15
|
+
Because remote links can potentially include any type of file, they are
|
|
16
|
+
not supported.
|
|
17
|
+
|
|
18
|
+
The function returns a dict in the similar manner as the benchmarks:
|
|
19
|
+
|
|
20
|
+
Examples:
|
|
21
|
+
- SKIP: {None: 'reason'}
|
|
22
|
+
- FAIL: {False: 'reason'}
|
|
23
|
+
- PASS: {ProjectFile, None}
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
import logging
|
|
27
|
+
import re
|
|
28
|
+
|
|
29
|
+
from gitlab.exceptions import (GitlabAuthenticationError, GitlabGetError,
|
|
30
|
+
GitlabHttpError)
|
|
31
|
+
|
|
32
|
+
try:
|
|
33
|
+
# set the default path if one is not set:
|
|
34
|
+
gitlabCiYamlPath = (
|
|
35
|
+
str(glEntity.ci_config_path)
|
|
36
|
+
if glEntity.ci_config_path != ''
|
|
37
|
+
else '.gitlab-ci.yml'
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
# SKIP remote CI files:
|
|
41
|
+
if '://' in gitlabCiYamlPath:
|
|
42
|
+
return {None: f'Remote CI file: {gitlabCiYamlPath} not supported'}
|
|
43
|
+
|
|
44
|
+
# handle different project locations:
|
|
45
|
+
remote = re.match(
|
|
46
|
+
r'(?P<filePath>.*)@(?P<namespace>.*):?(?P<refName>.*)',
|
|
47
|
+
gitlabCiYamlPath)
|
|
48
|
+
|
|
49
|
+
# define the location:
|
|
50
|
+
if remote is not None:
|
|
51
|
+
_tempEntity = glObject.projects.get(
|
|
52
|
+
remote.group('namespace')
|
|
53
|
+
)
|
|
54
|
+
_tempRef = remote.group('refName')
|
|
55
|
+
_tempPath = remote.group('filePath')
|
|
56
|
+
else:
|
|
57
|
+
_tempEntity = glEntity
|
|
58
|
+
_tempRef = glEntity.default_branch
|
|
59
|
+
_tempPath = gitlabCiYamlPath
|
|
60
|
+
|
|
61
|
+
# obtain the CI config file:
|
|
62
|
+
gitlabCiYaml = None
|
|
63
|
+
try:
|
|
64
|
+
gitlabCiYaml = _tempEntity.files.get(
|
|
65
|
+
file_path=_tempPath,
|
|
66
|
+
ref=_tempRef
|
|
67
|
+
)
|
|
68
|
+
except (GitlabHttpError, GitlabGetError) as e:
|
|
69
|
+
if e.response_code == 404:
|
|
70
|
+
logging.debug(f'No CI config file found at: {_tempPath}')
|
|
71
|
+
return {False: f'Pipeline config file not found: {_tempPath}'}
|
|
72
|
+
|
|
73
|
+
# return a dict with a ProjectFile class var as the key
|
|
74
|
+
# to differentiate results or not:
|
|
75
|
+
if gitlabCiYaml is not None:
|
|
76
|
+
return {gitlabCiYaml: None}
|
|
77
|
+
|
|
78
|
+
return {False: f'Pipeline config file not found: {_tempPath}'}
|
|
79
|
+
|
|
80
|
+
except (GitlabHttpError, GitlabGetError, GitlabAuthenticationError):
|
|
81
|
+
return {None: 'Insufficient permissions'}
|
|
82
|
+
|
|
83
|
+
# this is for pytest to run unauthed tests:
|
|
84
|
+
except AttributeError:
|
|
85
|
+
return {None: 'Insufficient permissions'}
|
|
86
|
+
|
|
87
|
+
# -------------------------------------------------------------------------
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def searchConfig(glEntity, glObject, searchString, **kwargs):
|
|
91
|
+
"""
|
|
92
|
+
This function allows to search for a string inside the .gitlab-ci.yml file
|
|
93
|
+
|
|
94
|
+
It uses the above getConfig() function to obtain it, then checks the str
|
|
95
|
+
based on its lowercase value.
|
|
96
|
+
"""
|
|
97
|
+
|
|
98
|
+
import base64
|
|
99
|
+
|
|
100
|
+
from gitlab.exceptions import (GitlabAuthenticationError, GitlabGetError,
|
|
101
|
+
GitlabHttpError)
|
|
102
|
+
from gitlab.v4.objects.files import ProjectFile
|
|
103
|
+
|
|
104
|
+
try:
|
|
105
|
+
# obtain the ci config file:
|
|
106
|
+
gitlabCiYaml = getConfig(
|
|
107
|
+
glEntity, glObject, **kwargs)
|
|
108
|
+
|
|
109
|
+
# obtain the result:
|
|
110
|
+
try:
|
|
111
|
+
_result = next(iter(gitlabCiYaml))
|
|
112
|
+
|
|
113
|
+
# a SKIP was identified:
|
|
114
|
+
except TypeError:
|
|
115
|
+
# ensure the reason is returned:
|
|
116
|
+
return {None: gitlabCiYaml[None]}
|
|
117
|
+
|
|
118
|
+
# ensure we actually found the file:
|
|
119
|
+
if not isinstance(_result, ProjectFile):
|
|
120
|
+
return {_result: gitlabCiYaml[_result]}
|
|
121
|
+
|
|
122
|
+
yamlContents = base64.b64decode(
|
|
123
|
+
_result.content).decode('utf-8')
|
|
124
|
+
|
|
125
|
+
if searchString.lower() in yamlContents.lower():
|
|
126
|
+
return {True: f'{searchString} was found in CI config file'}
|
|
127
|
+
else:
|
|
128
|
+
return {False: f'{searchString} was not found in CI config file'} # noqa: E713, E501
|
|
129
|
+
|
|
130
|
+
except (GitlabHttpError, GitlabGetError, GitlabAuthenticationError) as e:
|
|
131
|
+
if e.response_code in [401, 403]:
|
|
132
|
+
return {None: 'Insufficient permissions'}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 GitLab
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|