Commit 9ceb989a authored by rossfuhrman's avatar rossfuhrman Committed by Robert Speicher

Add support for SAST_EXCLUDED_ANALYZERS

Add SAST_EXCLUDED_ANALYZERS support in SAST so that we can move away
from SAST_DEFAULT_ANALYZERS in the future
parent fd12d684
...@@ -5,6 +5,8 @@ module Security ...@@ -5,6 +5,8 @@ module Security
# This class parses SAST template file and .gitlab-ci.yml to populate default and current values into the JSON # This class parses SAST template file and .gitlab-ci.yml to populate default and current values into the JSON
# read from app/validators/json_schemas/security_ci_configuration_schemas/sast_ui_schema.json # read from app/validators/json_schemas/security_ci_configuration_schemas/sast_ui_schema.json
class SastParserService < ::BaseService class SastParserService < ::BaseService
include Gitlab::Utils::StrongMemoize
SAST_UI_SCHEMA_PATH = 'app/validators/json_schemas/security_ci_configuration_schemas/sast_ui_schema.json' SAST_UI_SCHEMA_PATH = 'app/validators/json_schemas/security_ci_configuration_schemas/sast_ui_schema.json'
def initialize(project) def initialize(project)
...@@ -60,19 +62,35 @@ module Security ...@@ -60,19 +62,35 @@ module Security
def populate_current_value_for_analyzers(result) def populate_current_value_for_analyzers(result)
result[:analyzers].each do |analyzer| result[:analyzers].each do |analyzer|
analyzer[:enabled] = sast_default_analyzers.include?(analyzer[:name]) analyzer[:enabled] = analyzer_enabled?(analyzer[:name])
populate_current_value_for(analyzer, :variables) populate_current_value_for(analyzer, :variables)
end end
end end
def sast_template_attributes def analyzer_enabled?(analyzer_name)
@sast_template_attributes ||= build_sast_attributes(sast_template_content) # Unless explicitly listed in the excluded analyzers, consider it enabled
sast_excluded_analyzers.exclude?(analyzer_name)
end
def sast_excluded_analyzers
strong_memoize(:sast_excluded_analyzers) do
all_analyzers = Security::CiConfiguration::SastBuildActions::SAST_DEFAULT_ANALYZERS.split(', ') rescue []
enabled_analyzers = sast_default_analyzers.split(',').map(&:strip) rescue []
excluded_analyzers = gitlab_ci_yml_attributes["SAST_EXCLUDED_ANALYZERS"] || sast_template_attributes["SAST_EXCLUDED_ANALYZERS"]
excluded_analyzers = excluded_analyzers.split(',').map(&:strip) rescue []
((all_analyzers - enabled_analyzers) + excluded_analyzers).uniq
end
end end
def sast_default_analyzers def sast_default_analyzers
@sast_default_analyzers ||= gitlab_ci_yml_attributes["SAST_DEFAULT_ANALYZERS"] || sast_template_attributes["SAST_DEFAULT_ANALYZERS"] @sast_default_analyzers ||= gitlab_ci_yml_attributes["SAST_DEFAULT_ANALYZERS"] || sast_template_attributes["SAST_DEFAULT_ANALYZERS"]
end end
def sast_template_attributes
@sast_template_attributes ||= build_sast_attributes(sast_template_content)
end
def gitlab_ci_yml_attributes def gitlab_ci_yml_attributes
@gitlab_ci_yml_attributes ||= begin @gitlab_ci_yml_attributes ||= begin
config_content = @project.repository.blob_data_at(@project.repository.root_ref_sha, ci_config_file) config_content = @project.repository.blob_data_at(@project.repository.root_ref_sha, ci_config_file)
......
---
title: Add support for SAST_EXCLUDED_ANALYZERS
merge_request: 50872
author:
type: changed
...@@ -51,15 +51,15 @@ module Security ...@@ -51,15 +51,15 @@ module Security
&.flat_map {|a| a['variables'] } &.flat_map {|a| a['variables'] }
&.collect {|v| [v['field'], v[key]] }.to_h &.collect {|v| [v['field'], v[key]] }.to_h
analyzer_variables['SAST_DEFAULT_ANALYZERS'] = if key == 'value' analyzer_variables['SAST_EXCLUDED_ANALYZERS'] = if key == 'value'
config['analyzers'] config['analyzers']
&.select {|a| a['enabled'] } &.reject {|a| a['enabled'] }
&.collect {|a| a['name'] } &.collect {|a| a['name'] }
&.sort &.sort
&.join(', ') &.join(', ')
else else
SAST_DEFAULT_ANALYZERS ''
end end
analyzer_variables analyzer_variables
end end
...@@ -155,7 +155,7 @@ module Security ...@@ -155,7 +155,7 @@ module Security
SAST_ANALYZER_IMAGE_TAG SAST_ANALYZER_IMAGE_TAG
SAST_EXCLUDED_PATHS SAST_EXCLUDED_PATHS
SEARCH_MAX_DEPTH SEARCH_MAX_DEPTH
SAST_DEFAULT_ANALYZERS SAST_EXCLUDED_ANALYZERS
SAST_BRAKEMAN_LEVEL SAST_BRAKEMAN_LEVEL
SAST_BANDIT_EXCLUDED_PATHS SAST_BANDIT_EXCLUDED_PATHS
SAST_FLAWFINDER_LEVEL SAST_FLAWFINDER_LEVEL
......
...@@ -140,12 +140,24 @@ RSpec.describe Security::CiConfiguration::SastBuildActions do ...@@ -140,12 +140,24 @@ RSpec.describe Security::CiConfiguration::SastBuildActions do
expect(result.first[:content]).to eq(sast_yaml_with_no_variables_set_but_analyzers) expect(result.first[:content]).to eq(sast_yaml_with_no_variables_set_but_analyzers)
end end
context 'analyzers are disabled' do
let(:gitlab_ci_content) { existing_gitlab_ci_and_single_template_with_sast_and_default_stage }
subject(:result) { described_class.new(auto_devops_enabled, params_with_analyzer_info, gitlab_ci_content).generate }
it 'writes SAST_EXCLUDED_ANALYZERS' do
stub_const('Security::CiConfiguration::SastBuildActions::SAST_DEFAULT_ANALYZERS', 'bandit, brakeman, flawfinder')
expect(result.first[:content]).to eq(sast_yaml_with_no_variables_set_but_analyzers)
end
end
context 'all analyzers are enabled' do context 'all analyzers are enabled' do
let(:gitlab_ci_content) { existing_gitlab_ci_and_single_template_with_sast_and_default_stage } let(:gitlab_ci_content) { existing_gitlab_ci_and_single_template_with_sast_and_default_stage }
subject(:result) { described_class.new(auto_devops_enabled, params_with_all_analyzers_enabled, gitlab_ci_content).generate } subject(:result) { described_class.new(auto_devops_enabled, params_with_all_analyzers_enabled, gitlab_ci_content).generate }
it 'does not write SAST_DEFAULT_ANALYZERS' do it 'does not write SAST_DEFAULT_ANALYZERS or SAST_EXCLUDED_ANALYZERS' do
stub_const('Security::CiConfiguration::SastBuildActions::SAST_DEFAULT_ANALYZERS', 'brakeman, flawfinder') stub_const('Security::CiConfiguration::SastBuildActions::SAST_DEFAULT_ANALYZERS', 'brakeman, flawfinder')
expect(result.first[:content]).to eq(sast_yaml_with_no_variables_set) expect(result.first[:content]).to eq(sast_yaml_with_no_variables_set)
...@@ -335,7 +347,7 @@ RSpec.describe Security::CiConfiguration::SastBuildActions do ...@@ -335,7 +347,7 @@ RSpec.describe Security::CiConfiguration::SastBuildActions do
- test - test
sast: sast:
variables: variables:
SAST_DEFAULT_ANALYZERS: brakeman, flawfinder SAST_EXCLUDED_ANALYZERS: bandit
SAST_BRAKEMAN_LEVEL: '2' SAST_BRAKEMAN_LEVEL: '2'
stage: test stage: test
include: include:
......
...@@ -13,6 +13,7 @@ RSpec.describe Security::CiConfiguration::SastParserService do ...@@ -13,6 +13,7 @@ RSpec.describe Security::CiConfiguration::SastParserService do
let(:sast_pipeline_stage) { configuration['pipeline'][0] } let(:sast_pipeline_stage) { configuration['pipeline'][0] }
let(:sast_search_max_depth) { configuration['pipeline'][1] } let(:sast_search_max_depth) { configuration['pipeline'][1] }
let(:brakeman) { configuration['analyzers'][0] } let(:brakeman) { configuration['analyzers'][0] }
let(:bandit) { configuration['analyzers'][1] }
let(:sast_brakeman_level) { brakeman['variables'][0] } let(:sast_brakeman_level) { brakeman['variables'][0] }
it 'parses the configuration for SAST' do it 'parses the configuration for SAST' do
...@@ -35,8 +36,27 @@ RSpec.describe Security::CiConfiguration::SastParserService do ...@@ -35,8 +36,27 @@ RSpec.describe Security::CiConfiguration::SastParserService do
expect(sast_pipeline_stage['value']).to eql('our_custom_security_stage') expect(sast_pipeline_stage['value']).to eql('our_custom_security_stage')
expect(sast_search_max_depth['value']).to eql('8') expect(sast_search_max_depth['value']).to eql('8')
expect(brakeman['enabled']).to be(false) expect(brakeman['enabled']).to be(false)
expect(bandit['enabled']).to be(true)
expect(sast_brakeman_level['value']).to eql('2') expect(sast_brakeman_level['value']).to eql('2')
end end
context 'SAST_DEFAULT_ANALYZERS is set' do
it 'enables analyzers correctly' do
allow(project.repository).to receive(:blob_data_at).and_return(gitlab_ci_yml_default_analyzers_content)
expect(brakeman['enabled']).to be(false)
expect(bandit['enabled']).to be(true)
end
end
context 'SAST_EXCLUDED_ANALYZERS is set' do
it 'enables analyzers correctly' do
allow(project.repository).to receive(:blob_data_at).and_return(gitlab_ci_yml_excluded_analyzers_content)
expect(brakeman['enabled']).to be(false)
expect(bandit['enabled']).to be(true)
end
end
end end
context 'when .gitlab-ci.yml is absent' do context 'when .gitlab-ci.yml is absent' do
......
...@@ -10,6 +10,7 @@ variables: ...@@ -10,6 +10,7 @@ variables:
SECURE_ANALYZERS_PREFIX: "registry.gitlab.com/gitlab-org/security-products/analyzers" SECURE_ANALYZERS_PREFIX: "registry.gitlab.com/gitlab-org/security-products/analyzers"
SAST_DEFAULT_ANALYZERS: "bandit, brakeman, gosec, spotbugs, flawfinder, phpcs-security-audit, security-code-scan, nodejs-scan, eslint, sobelow, pmd-apex, kubesec, mobsf" SAST_DEFAULT_ANALYZERS: "bandit, brakeman, gosec, spotbugs, flawfinder, phpcs-security-audit, security-code-scan, nodejs-scan, eslint, sobelow, pmd-apex, kubesec, mobsf"
SAST_EXCLUDED_ANALYZERS: ""
SAST_EXCLUDED_PATHS: "spec, test, tests, tmp" SAST_EXCLUDED_PATHS: "spec, test, tests, tmp"
SAST_ANALYZER_IMAGE_TAG: 2 SAST_ANALYZER_IMAGE_TAG: 2
SCAN_KUBERNETES_MANIFESTS: "false" SCAN_KUBERNETES_MANIFESTS: "false"
...@@ -44,6 +45,8 @@ bandit-sast: ...@@ -44,6 +45,8 @@ bandit-sast:
rules: rules:
- if: $SAST_DISABLED - if: $SAST_DISABLED
when: never when: never
- if: $SAST_EXCLUDED_ANALYZERS =~ /bandit/
when: never
- if: $CI_COMMIT_BRANCH && - if: $CI_COMMIT_BRANCH &&
$SAST_DEFAULT_ANALYZERS =~ /bandit/ $SAST_DEFAULT_ANALYZERS =~ /bandit/
exists: exists:
...@@ -58,6 +61,8 @@ brakeman-sast: ...@@ -58,6 +61,8 @@ brakeman-sast:
rules: rules:
- if: $SAST_DISABLED - if: $SAST_DISABLED
when: never when: never
- if: $SAST_EXCLUDED_ANALYZERS =~ /brakeman/
when: never
- if: $CI_COMMIT_BRANCH && - if: $CI_COMMIT_BRANCH &&
$SAST_DEFAULT_ANALYZERS =~ /brakeman/ $SAST_DEFAULT_ANALYZERS =~ /brakeman/
exists: exists:
...@@ -72,6 +77,8 @@ eslint-sast: ...@@ -72,6 +77,8 @@ eslint-sast:
rules: rules:
- if: $SAST_DISABLED - if: $SAST_DISABLED
when: never when: never
- if: $SAST_EXCLUDED_ANALYZERS =~ /eslint/
when: never
- if: $CI_COMMIT_BRANCH && - if: $CI_COMMIT_BRANCH &&
$SAST_DEFAULT_ANALYZERS =~ /eslint/ $SAST_DEFAULT_ANALYZERS =~ /eslint/
exists: exists:
...@@ -90,6 +97,8 @@ flawfinder-sast: ...@@ -90,6 +97,8 @@ flawfinder-sast:
rules: rules:
- if: $SAST_DISABLED - if: $SAST_DISABLED
when: never when: never
- if: $SAST_EXCLUDED_ANALYZERS =~ /flawfinder/
when: never
- if: $CI_COMMIT_BRANCH && - if: $CI_COMMIT_BRANCH &&
$SAST_DEFAULT_ANALYZERS =~ /flawfinder/ $SAST_DEFAULT_ANALYZERS =~ /flawfinder/
exists: exists:
...@@ -105,6 +114,8 @@ kubesec-sast: ...@@ -105,6 +114,8 @@ kubesec-sast:
rules: rules:
- if: $SAST_DISABLED - if: $SAST_DISABLED
when: never when: never
- if: $SAST_EXCLUDED_ANALYZERS =~ /kubesec/
when: never
- if: $CI_COMMIT_BRANCH && - if: $CI_COMMIT_BRANCH &&
$SAST_DEFAULT_ANALYZERS =~ /kubesec/ && $SAST_DEFAULT_ANALYZERS =~ /kubesec/ &&
$SCAN_KUBERNETES_MANIFESTS == 'true' $SCAN_KUBERNETES_MANIFESTS == 'true'
...@@ -118,6 +129,8 @@ gosec-sast: ...@@ -118,6 +129,8 @@ gosec-sast:
rules: rules:
- if: $SAST_DISABLED - if: $SAST_DISABLED
when: never when: never
- if: $SAST_EXCLUDED_ANALYZERS =~ /gosec/
when: never
- if: $CI_COMMIT_BRANCH && - if: $CI_COMMIT_BRANCH &&
$SAST_DEFAULT_ANALYZERS =~ /gosec/ $SAST_DEFAULT_ANALYZERS =~ /gosec/
exists: exists:
...@@ -136,6 +149,8 @@ mobsf-android-sast: ...@@ -136,6 +149,8 @@ mobsf-android-sast:
rules: rules:
- if: $SAST_DISABLED - if: $SAST_DISABLED
when: never when: never
- if: $SAST_EXCLUDED_ANALYZERS =~ /mobsf/
when: never
- if: $CI_COMMIT_BRANCH && - if: $CI_COMMIT_BRANCH &&
$SAST_DEFAULT_ANALYZERS =~ /mobsf/ && $SAST_DEFAULT_ANALYZERS =~ /mobsf/ &&
$SAST_EXPERIMENTAL_FEATURES == 'true' $SAST_EXPERIMENTAL_FEATURES == 'true'
...@@ -155,6 +170,8 @@ mobsf-ios-sast: ...@@ -155,6 +170,8 @@ mobsf-ios-sast:
rules: rules:
- if: $SAST_DISABLED - if: $SAST_DISABLED
when: never when: never
- if: $SAST_EXCLUDED_ANALYZERS =~ /mobsf/
when: never
- if: $CI_COMMIT_BRANCH && - if: $CI_COMMIT_BRANCH &&
$SAST_DEFAULT_ANALYZERS =~ /mobsf/ && $SAST_DEFAULT_ANALYZERS =~ /mobsf/ &&
$SAST_EXPERIMENTAL_FEATURES == 'true' $SAST_EXPERIMENTAL_FEATURES == 'true'
...@@ -170,6 +187,8 @@ nodejs-scan-sast: ...@@ -170,6 +187,8 @@ nodejs-scan-sast:
rules: rules:
- if: $SAST_DISABLED - if: $SAST_DISABLED
when: never when: never
- if: $SAST_EXCLUDED_ANALYZERS =~ /nodejs-scan/
when: never
- if: $CI_COMMIT_BRANCH && - if: $CI_COMMIT_BRANCH &&
$SAST_DEFAULT_ANALYZERS =~ /nodejs-scan/ $SAST_DEFAULT_ANALYZERS =~ /nodejs-scan/
exists: exists:
...@@ -184,6 +203,8 @@ phpcs-security-audit-sast: ...@@ -184,6 +203,8 @@ phpcs-security-audit-sast:
rules: rules:
- if: $SAST_DISABLED - if: $SAST_DISABLED
when: never when: never
- if: $SAST_EXCLUDED_ANALYZERS =~ /phpcs-security-audit/
when: never
- if: $CI_COMMIT_BRANCH && - if: $CI_COMMIT_BRANCH &&
$SAST_DEFAULT_ANALYZERS =~ /phpcs-security-audit/ $SAST_DEFAULT_ANALYZERS =~ /phpcs-security-audit/
exists: exists:
...@@ -198,6 +219,8 @@ pmd-apex-sast: ...@@ -198,6 +219,8 @@ pmd-apex-sast:
rules: rules:
- if: $SAST_DISABLED - if: $SAST_DISABLED
when: never when: never
- if: $SAST_EXCLUDED_ANALYZERS =~ /pmd-apex/
when: never
- if: $CI_COMMIT_BRANCH && - if: $CI_COMMIT_BRANCH &&
$SAST_DEFAULT_ANALYZERS =~ /pmd-apex/ $SAST_DEFAULT_ANALYZERS =~ /pmd-apex/
exists: exists:
...@@ -212,6 +235,8 @@ security-code-scan-sast: ...@@ -212,6 +235,8 @@ security-code-scan-sast:
rules: rules:
- if: $SAST_DISABLED - if: $SAST_DISABLED
when: never when: never
- if: $SAST_EXCLUDED_ANALYZERS =~ /security-code-scan/
when: never
- if: $CI_COMMIT_BRANCH && - if: $CI_COMMIT_BRANCH &&
$SAST_DEFAULT_ANALYZERS =~ /security-code-scan/ $SAST_DEFAULT_ANALYZERS =~ /security-code-scan/
exists: exists:
...@@ -227,6 +252,8 @@ sobelow-sast: ...@@ -227,6 +252,8 @@ sobelow-sast:
rules: rules:
- if: $SAST_DISABLED - if: $SAST_DISABLED
when: never when: never
- if: $SAST_EXCLUDED_ANALYZERS =~ /sobelow/
when: never
- if: $CI_COMMIT_BRANCH && - if: $CI_COMMIT_BRANCH &&
$SAST_DEFAULT_ANALYZERS =~ /sobelow/ $SAST_DEFAULT_ANALYZERS =~ /sobelow/
exists: exists:
...@@ -239,6 +266,8 @@ spotbugs-sast: ...@@ -239,6 +266,8 @@ spotbugs-sast:
variables: variables:
SAST_ANALYZER_IMAGE: "$SECURE_ANALYZERS_PREFIX/spotbugs:$SAST_ANALYZER_IMAGE_TAG" SAST_ANALYZER_IMAGE: "$SECURE_ANALYZERS_PREFIX/spotbugs:$SAST_ANALYZER_IMAGE_TAG"
rules: rules:
- if: $SAST_EXCLUDED_ANALYZERS =~ /spotbugs/
when: never
- if: $SAST_DEFAULT_ANALYZERS =~ /mobsf/ && - if: $SAST_DEFAULT_ANALYZERS =~ /mobsf/ &&
$SAST_EXPERIMENTAL_FEATURES == 'true' $SAST_EXPERIMENTAL_FEATURES == 'true'
exists: exists:
......
...@@ -4,7 +4,8 @@ include: ...@@ -4,7 +4,8 @@ include:
variables: variables:
SECURE_ANALYZERS_PREFIX: "registry.gitlab.com/gitlab-org/security-products/analyzers2" SECURE_ANALYZERS_PREFIX: "registry.gitlab.com/gitlab-org/security-products/analyzers2"
SAST_EXCLUDED_PATHS: "spec, executables" SAST_EXCLUDED_PATHS: "spec, executables"
SAST_DEFAULT_ANALYZERS: "bandit, gosec" SAST_DEFAULT_ANALYZERS: "bandit, brakeman"
SAST_EXCLUDED_ANALYZERS: "brakeman"
stages: stages:
- our_custom_security_stage - our_custom_security_stage
......
include:
- template: SAST.gitlab-ci.yml
variables:
SECURE_ANALYZERS_PREFIX: "registry.gitlab.com/gitlab-org/security-products/analyzers2"
SAST_EXCLUDED_PATHS: "spec, executables"
SAST_DEFAULT_ANALYZERS: "bandit, gosec"
stages:
- our_custom_security_stage
sast:
stage: our_custom_security_stage
variables:
SEARCH_MAX_DEPTH: 8
SAST_BRAKEMAN_LEVEL: 2
include:
- template: SAST.gitlab-ci.yml
variables:
SECURE_ANALYZERS_PREFIX: "registry.gitlab.com/gitlab-org/security-products/analyzers2"
SAST_EXCLUDED_PATHS: "spec, executables"
SAST_EXCLUDED_ANALYZERS: "brakeman"
stages:
- our_custom_security_stage
sast:
stage: our_custom_security_stage
variables:
SEARCH_MAX_DEPTH: 8
...@@ -5,5 +5,13 @@ RSpec.shared_context 'read ci configuration for sast enabled project' do ...@@ -5,5 +5,13 @@ RSpec.shared_context 'read ci configuration for sast enabled project' do
File.read(Rails.root.join('spec/support/gitlab_stubs/gitlab_ci_for_sast.yml')) File.read(Rails.root.join('spec/support/gitlab_stubs/gitlab_ci_for_sast.yml'))
end end
let_it_be(:gitlab_ci_yml_default_analyzers_content) do
File.read(Rails.root.join('spec/support/gitlab_stubs/gitlab_ci_for_sast_default_analyzers.yml'))
end
let_it_be(:gitlab_ci_yml_excluded_analyzers_content) do
File.read(Rails.root.join('spec/support/gitlab_stubs/gitlab_ci_for_sast_excluded_analyzers.yml'))
end
let_it_be(:project) { create(:project, :repository) } let_it_be(:project) { create(:project, :repository) }
end end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment