diff --git a/doc/user/application_security/secret_detection/secret_push_protection/index.md b/doc/user/application_security/secret_detection/secret_push_protection/index.md index 62b1f744802fd894365262c97af95a46e4f91a15..5e384c6fe668b553295166f6cea2e62d38e1270f 100644 --- a/doc/user/application_security/secret_detection/secret_push_protection/index.md +++ b/doc/user/application_security/secret_detection/secret_push_protection/index.md @@ -117,6 +117,10 @@ This can cause a [push to be blocked unexpectedly](#push-blocked-unexpectedly) w You can enable the `spp_scan_diffs` [feature flag](../../../../administration/feature_flags.md) for your project, which modifies Secret Push Protection to only scan newly committed changes (or diffs), and not the rest of the file. +When `spp_scan_diffs` is enabled, Secret Push Protection scans the diffs for CLI-based pushes via HTTP/SSH. +Changes committed via the WebIDE still result in the entire file being scanned due to a technical limitation. +[Issue 491282](https://gitlab.com/gitlab-org/gitlab/-/issues/491282) addresses the limitation so only the diffs are scanned for WebIDE changes. + ## Resolve a blocked push When secret push protection blocks a push, you can either: @@ -210,6 +214,7 @@ Secret Push Protection scans all contents of modified files. This can cause a pu if a modified file contains a secret, even if the secret is not part of the diff. [Enable the `spp_scan_diffs` feature flag](#diff-scanning) to ensure that only newly committed changes are scanned. +To push a WebIDE change to a file that contains a secret, you need to [skip secret push protection](#skip-secret-push-protection). ### File was not scanned diff --git a/ee/lib/gitlab/checks/secrets_check.rb b/ee/lib/gitlab/checks/secrets_check.rb index 74c1b8e2fc6cc4873a906e08f4b1b1ca2a5a5f41..7c54afbcb96a91c9db22af21750693a31d997391 100644 --- a/ee/lib/gitlab/checks/secrets_check.rb +++ b/ee/lib/gitlab/checks/secrets_check.rb @@ -68,7 +68,7 @@ def validate! end logger.log_timed(LOG_MESSAGES[:secrets_check]) do - if Feature.enabled?(:spp_scan_diffs, project) + if use_diff_scan? payloads = get_diffs # Pass payloads to gem for scanning. response = ::Gitlab::SecretDetection::ScanDiffs @@ -99,6 +99,14 @@ def validate! private + def http_or_ssh_protocol? + %w[http ssh].include?(changes_access.protocol) + end + + def use_diff_scan? + Feature.enabled?(:spp_scan_diffs, project) && http_or_ssh_protocol? + end + def run_pre_receive_secret_detection? Gitlab::CurrentSettings.current_application_settings.pre_receive_secret_detection_enabled && (enabled_for_non_dedicated_project? || enabled_for_dedicated_project?) diff --git a/ee/spec/lib/gitlab/checks/secrets_check_spec.rb b/ee/spec/lib/gitlab/checks/secrets_check_spec.rb index dd0ed5a964dc8c7d170d39e6b3825596bdc72c24..00b19bf89527a147502eca4a97f988eed237e5c1 100644 --- a/ee/spec/lib/gitlab/checks/secrets_check_spec.rb +++ b/ee/spec/lib/gitlab/checks/secrets_check_spec.rb @@ -56,16 +56,32 @@ it_behaves_like 'skips the push check' end - it_behaves_like 'diff scan passed' - it_behaves_like 'diff scan detected secrets' - it_behaves_like 'diff scan detected secrets but some errors occured' - it_behaves_like 'diff scan timed out' - it_behaves_like 'diff scan failed to initialize' - it_behaves_like 'diff scan failed with invalid input' - it_behaves_like 'diff scan handles malformed blobs' - it_behaves_like 'diff scan skipped due to invalid status' - it_behaves_like 'diff scan skipped when a commit has special bypass flag' - it_behaves_like 'diff scan skipped when secret_push_protection.skip_all push option is passed' + context 'when the spp_scan_diffs flag is enabled' do + it_behaves_like 'diff scan passed' + it_behaves_like 'diff scan detected secrets' + it_behaves_like 'diff scan detected secrets but some errors occured' + it_behaves_like 'diff scan timed out' + it_behaves_like 'diff scan failed to initialize' + it_behaves_like 'diff scan failed with invalid input' + it_behaves_like 'diff scan handles malformed blobs' + it_behaves_like 'diff scan skipped due to invalid status' + it_behaves_like 'diff scan skipped when a commit has special bypass flag' + it_behaves_like 'diff scan skipped when secret_push_protection.skip_all push option is passed' + + context 'when the protocol is web' do + subject(:secrets_check) { described_class.new(changes_access_web) } + + it_behaves_like 'scan passed' + it_behaves_like 'scan detected secrets' + it_behaves_like 'scan detected secrets but some errors occured' + it_behaves_like 'scan timed out' + it_behaves_like 'scan failed to initialize' + it_behaves_like 'scan failed with invalid input' + it_behaves_like 'scan skipped due to invalid status' + it_behaves_like 'scan skipped when a commit has special bypass flag' + it_behaves_like 'scan skipped when secret_push_protection.skip_all push option is passed' + end + end context 'when the scan diff feature flag is not enabled' do before do @@ -81,6 +97,20 @@ it_behaves_like 'scan skipped due to invalid status' it_behaves_like 'scan skipped when a commit has special bypass flag' it_behaves_like 'scan skipped when secret_push_protection.skip_all push option is passed' + + context 'when the protocol is web' do + subject(:secrets_check) { described_class.new(changes_access_web) } + + it_behaves_like 'scan passed' + it_behaves_like 'scan detected secrets' + it_behaves_like 'scan detected secrets but some errors occured' + it_behaves_like 'scan timed out' + it_behaves_like 'scan failed to initialize' + it_behaves_like 'scan failed with invalid input' + it_behaves_like 'scan skipped due to invalid status' + it_behaves_like 'scan skipped when a commit has special bypass flag' + it_behaves_like 'scan skipped when secret_push_protection.skip_all push option is passed' + end end end end diff --git a/ee/spec/support/shared_contexts/secrets_check_shared_contexts.rb b/ee/spec/support/shared_contexts/secrets_check_shared_contexts.rb index ed9ba59030851e65e35b473402bf67621af7360d..e6ed8c88120f247539e18b42e80fee675c15f573 100644 --- a/ee/spec/support/shared_contexts/secrets_check_shared_contexts.rb +++ b/ee/spec/support/shared_contexts/secrets_check_shared_contexts.rb @@ -88,6 +88,17 @@ ) end + let(:changes_access_web) do + Gitlab::Checks::ChangesAccess.new( + changes, + project: project, + user_access: user_access, + protocol: 'web', + logger: logger, + push_options: push_options + ) + end + let(:delete_changes_access) do Gitlab::Checks::ChangesAccess.new( delete_changes, diff --git a/ee/spec/support/shared_examples/lib/gitlab/secrets_check_shared_examples.rb b/ee/spec/support/shared_examples/lib/gitlab/secrets_check_shared_examples.rb index c32ef179a65034a5f6c5570940ea7649266d30a5..396e48f367406725d073685215e85aca0e9faf38 100644 --- a/ee/spec/support/shared_examples/lib/gitlab/secrets_check_shared_examples.rb +++ b/ee/spec/support/shared_examples/lib/gitlab/secrets_check_shared_examples.rb @@ -1136,6 +1136,8 @@ ) end + subject(:secrets_check) { described_class.new(changes_access) } + let_it_be(:new_commit) do create_commit( { '.env' => 'SECRET=glpat-JUST20LETTERSANDNUMB' } # gitleaks:allow