diff --git a/ee/config/feature_flags/development/pre_receive_secret_detection_push_check.yml b/ee/config/feature_flags/development/pre_receive_secret_detection_push_check.yml new file mode 100644 index 0000000000000000000000000000000000000000..0005304987c6eaa340e33d81c08cc0b0cdae6ef7 --- /dev/null +++ b/ee/config/feature_flags/development/pre_receive_secret_detection_push_check.yml @@ -0,0 +1,8 @@ +--- +name: pre_receive_secret_detection_push_check +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/135032 +rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/429287 +milestone: '16.6' +type: development +group: group::static analysis +default_enabled: false diff --git a/ee/lib/ee/gitlab/checks/push_rule_check.rb b/ee/lib/ee/gitlab/checks/push_rule_check.rb index 10cff97a08a20e33d77c5caf1494418357bf6137..67a7c9b9dff23679f50f2a3754b7966ee0bf9200 100644 --- a/ee/lib/ee/gitlab/checks/push_rule_check.rb +++ b/ee/lib/ee/gitlab/checks/push_rule_check.rb @@ -38,6 +38,14 @@ def check_file_size! nil end + # @return [Nil] returns nil unless an error is raised + # @raise [Gitlab::GitAccess::ForbiddenError] if check fails + def check_secrets! + PushRules::SecretsCheck.new(changes_access).validate! + + nil + end + # Run the checks one after the other. # # @return [Nil] returns nil unless an error is raised @@ -45,6 +53,7 @@ def check_file_size! def run_checks_in_sequence! check_tag_or_branch! check_file_size! + check_secrets! end # Run the checks in separate threads for performance benefits. @@ -67,6 +76,10 @@ def run_checks_in_parallel! check_file_size! end + parallelize(git_env) do + check_secrets! + end + # Block whilst waiting for threads, however if one errors # it will exit early and raise the error immediately as # we set `abort_on_exception` to true. diff --git a/ee/lib/ee/gitlab/checks/push_rules/secrets_check.rb b/ee/lib/ee/gitlab/checks/push_rules/secrets_check.rb new file mode 100644 index 0000000000000000000000000000000000000000..1367887ef0142aa62b5edd1901ac260373b8c6e9 --- /dev/null +++ b/ee/lib/ee/gitlab/checks/push_rules/secrets_check.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +module EE + module Gitlab + module Checks + module PushRules + class SecretsCheck < ::Gitlab::Checks::BaseBulkChecker + def validate! + # Return early and not perform the check if: + # 1. no push rule exist + # 2. feature flag is disabled + return unless push_rule && ::Feature.enabled?(:pre_receive_secret_detection_push_check, push_rule.project) + end + end + end + end + end +end diff --git a/ee/spec/lib/ee/gitlab/checks/push_rule_check_spec.rb b/ee/spec/lib/ee/gitlab/checks/push_rule_check_spec.rb index 92b1adf5afc4f1a53cbfe84b02393b2475b0bfad..776638fa526276ae1917545518e8b762b5d78c13 100644 --- a/ee/spec/lib/ee/gitlab/checks/push_rule_check_spec.rb +++ b/ee/spec/lib/ee/gitlab/checks/push_rule_check_spec.rb @@ -16,6 +16,8 @@ shared_examples "push checks" do before do + allow_any_instance_of(EE::Gitlab::Checks::PushRules::SecretsCheck) + .to receive(:validate!).and_return(nil) allow_any_instance_of(EE::Gitlab::Checks::PushRules::FileSizeCheck) .to receive(:validate!).and_return(nil) allow_any_instance_of(EE::Gitlab::Checks::PushRules::TagCheck) diff --git a/ee/spec/lib/ee/gitlab/checks/push_rules/secrets_check_spec.rb b/ee/spec/lib/ee/gitlab/checks/push_rules/secrets_check_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..fe005f3fa4501e13b76a5eba1d96d782dbe80f97 --- /dev/null +++ b/ee/spec/lib/ee/gitlab/checks/push_rules/secrets_check_spec.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe EE::Gitlab::Checks::PushRules::SecretsCheck, feature_category: :secret_detection do + include_context 'push rules checks context' + + let_it_be(:push_rule) { create(:push_rule) } + + describe '#validate!' do + it_behaves_like 'check ignored when push rule unlicensed' + it_behaves_like 'use predefined push rules' + + context 'when feature flag is disabled' do + before do + stub_feature_flags(pre_receive_secret_detection_push_check: false) + end + + it 'skips the check' do + expect(subject.validate!).to be_nil + end + end + end +end