Commit fd1af13b authored by Alan (Maciej) Paruszewski's avatar Alan (Maciej) Paruszewski Committed by Robert Speicher

Add support for SAST in security policies

parent 0255ba46
...@@ -13602,7 +13602,7 @@ four standard [pagination arguments](#connection-pagination-arguments): ...@@ -13602,7 +13602,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
| Name | Type | Description | | Name | Type | Description |
| ---- | ---- | ----------- | | ---- | ---- | ----------- |
| <a id="projectscanexecutionpoliciesactionscantypes"></a>`actionScanTypes` | [`[SecurityReportTypeEnum!]`](#securityreporttypeenum) | Filters policies by the action scan type. Only these scan types are supported: `dast`, `secret_detection`, `cluster_image_scanning`, `container_scanning`. | | <a id="projectscanexecutionpoliciesactionscantypes"></a>`actionScanTypes` | [`[SecurityReportTypeEnum!]`](#securityreporttypeenum) | Filters policies by the action scan type. Only these scan types are supported: `dast`, `secret_detection`, `cluster_image_scanning`, `container_scanning`, `sast`. |
##### `Project.sentryDetailedError` ##### `Project.sentryDetailedError`
...@@ -307,7 +307,7 @@ rule in the defined policy are met. ...@@ -307,7 +307,7 @@ rule in the defined policy are met.
| Field | Type | Possible values | Description | | Field | Type | Possible values | Description |
|-------|------|-----------------|-------------| |-------|------|-----------------|-------------|
| `scan` | `string` | `dast`, `secret_detection` | The action's type. | | `scan` | `string` | `dast`, `secret_detection`, `sast` | The action's type. |
| `site_profile` | `string` | Name of the selected [DAST site profile](../dast/index.md#site-profile). | The DAST site profile to execute the DAST scan. This field should only be set if `scan` type is `dast`. | | `site_profile` | `string` | Name of the selected [DAST site profile](../dast/index.md#site-profile). | The DAST site profile to execute the DAST scan. This field should only be set if `scan` type is `dast`. |
| `scanner_profile` | `string` or `null` | Name of the selected [DAST scanner profile](../dast/index.md#scanner-profile). | The DAST scanner profile to execute the DAST scan. This field should only be set if `scan` type is `dast`.| | `scanner_profile` | `string` or `null` | Name of the selected [DAST scanner profile](../dast/index.md#scanner-profile). | The DAST scanner profile to execute the DAST scan. This field should only be set if `scan` type is `dast`.|
...@@ -330,6 +330,7 @@ Note the following: ...@@ -330,6 +330,7 @@ Note the following:
- A container scanning and cluster image scanning scans configured for the `pipeline` rule type will ignore the cluster defined in the `clusters` object. - A container scanning and cluster image scanning scans configured for the `pipeline` rule type will ignore the cluster defined in the `clusters` object.
They will use predefined CI/CD variables defined for your project. Cluster selection with the `clusters` object is supported for the `schedule` rule type. They will use predefined CI/CD variables defined for your project. Cluster selection with the `clusters` object is supported for the `schedule` rule type.
Cluster with name provided in `clusters` object must be created and configured for the project. To be able to successfully perform the `container_scanning`/`cluster_image_scanning` scans for the cluster you must follow instructions for the [Cluster Image Scanning feature](../cluster_image_scanning/index.md#prerequisites). Cluster with name provided in `clusters` object must be created and configured for the project. To be able to successfully perform the `container_scanning`/`cluster_image_scanning` scans for the cluster you must follow instructions for the [Cluster Image Scanning feature](../cluster_image_scanning/index.md#prerequisites).
- The SAST scan uses the default template and runs in a [child pipeline](../../../ci/pipelines/parent_child_pipelines.md).
### Example security policies project ### Example security policies project
......
...@@ -11,7 +11,7 @@ module Security ...@@ -11,7 +11,7 @@ module Security
schedule: 'schedule' schedule: 'schedule'
}.freeze }.freeze
SCAN_TYPES = %w[dast secret_detection cluster_image_scanning container_scanning].freeze SCAN_TYPES = %w[dast secret_detection cluster_image_scanning container_scanning sast].freeze
ON_DEMAND_SCANS = %w[dast].freeze ON_DEMAND_SCANS = %w[dast].freeze
included do included do
......
...@@ -6,7 +6,8 @@ module Security ...@@ -6,7 +6,8 @@ module Security
SCAN_TEMPLATES = { SCAN_TEMPLATES = {
'secret_detection' => 'Jobs/Secret-Detection', 'secret_detection' => 'Jobs/Secret-Detection',
'cluster_image_scanning' => 'Security/Cluster-Image-Scanning', 'cluster_image_scanning' => 'Security/Cluster-Image-Scanning',
'container_scanning' => 'Security/Container-Scanning' 'container_scanning' => 'Security/Container-Scanning',
'sast' => 'Security/SAST'
}.freeze }.freeze
def execute(action, ci_variables) def execute(action, ci_variables)
...@@ -15,6 +16,8 @@ module Security ...@@ -15,6 +16,8 @@ module Security
secret_detection_configuration(ci_variables) secret_detection_configuration(ci_variables)
when 'container_scanning', 'cluster_image_scanning' when 'container_scanning', 'cluster_image_scanning'
scan_configuration(action[:scan], ci_variables) scan_configuration(action[:scan], ci_variables)
when 'sast'
child_pipeline_configuration(action[:scan])
else else
error_script('Invalid Scan type') error_script('Invalid Scan type')
end end
...@@ -44,6 +47,17 @@ module Security ...@@ -44,6 +47,17 @@ module Security
.except(:rules) .except(:rules)
end end
def child_pipeline_configuration(template)
{
inherit: {
variables: false
},
trigger: {
include: [{ template: "#{SCAN_TEMPLATES[template.to_s]}.gitlab-ci.yml" }]
}
}
end
def error_script(error_message) def error_script(error_message)
{ {
'script' => "echo \"Error during Scan execution: #{error_message}\" && false", 'script' => "echo \"Error during Scan execution: #{error_message}\" && false",
......
...@@ -25,6 +25,7 @@ module Security ...@@ -25,6 +25,7 @@ module Security
when 'container_scanning' then schedule_container_scanning_scan(action, schedule, branches) when 'container_scanning' then schedule_container_scanning_scan(action, schedule, branches)
when 'cluster_image_scanning' then schedule_cluster_image_scanning_scan(action, schedule) when 'cluster_image_scanning' then schedule_cluster_image_scanning_scan(action, schedule)
when 'dast' then schedule_dast_on_demand_scan(action, branches) when 'dast' then schedule_dast_on_demand_scan(action, branches)
when 'sast' then schedule_scan(action, branches)
end end
end end
......
...@@ -119,7 +119,8 @@ ...@@ -119,7 +119,8 @@
"dast", "dast",
"secret_detection", "secret_detection",
"container_scanning", "container_scanning",
"cluster_image_scanning" "cluster_image_scanning",
"sast"
], ],
"type": "string" "type": "string"
}, },
...@@ -184,6 +185,18 @@ ...@@ -184,6 +185,18 @@
"then": { "then": {
"maxProperties": 1 "maxProperties": 1
} }
},
{
"if": {
"properties": {
"scan": {
"const": "sast"
}
}
},
"then": {
"maxProperties": 1
}
} }
], ],
"additionalProperties": false "additionalProperties": false
......
...@@ -112,6 +112,20 @@ RSpec.describe Security::SecurityOrchestrationPolicies::CiConfigurationService d ...@@ -112,6 +112,20 @@ RSpec.describe Security::SecurityOrchestrationPolicies::CiConfigurationService d
expect(subject.deep_symbolize_keys).to eq(expected_configuration) expect(subject.deep_symbolize_keys).to eq(expected_configuration)
end end
end end
context 'when scan type is sast' do
let_it_be(:action) { { scan: 'sast' } }
let_it_be(:ci_variables) { {} }
it 'returns prepared CI configuration for SAST' do
expected_configuration = {
inherit: { variables: false },
trigger: { include: [{ template: 'Security/SAST.gitlab-ci.yml' }] }
}
expect(subject.deep_symbolize_keys).to eq(expected_configuration)
end
end
end end
context 'when action is invalid' do context 'when action is invalid' do
......
...@@ -125,6 +125,16 @@ RSpec.describe Security::SecurityOrchestrationPolicies::CreatePipelineService do ...@@ -125,6 +125,16 @@ RSpec.describe Security::SecurityOrchestrationPolicies::CreatePipelineService do
expect(build.name).to eq('container_scanning') expect(build.name).to eq('container_scanning')
end end
end end
context 'for sast scan' do
let(:action) { { scan: 'sast' } }
it 'sets the build name to sast' do
build = pipeline.bridges.first
expect(build.name).to eq('sast')
end
end
end end
end end
end end
......
...@@ -124,6 +124,32 @@ RSpec.describe Security::SecurityOrchestrationPolicies::RuleScheduleService do ...@@ -124,6 +124,32 @@ RSpec.describe Security::SecurityOrchestrationPolicies::RuleScheduleService do
end end
end end
context 'when scan type is sast' do
before do
policy[:actions] = [{ scan: 'sast' }]
end
it 'invokes Security::SecurityOrchestrationPolicies::CreatePipelineService for both branches' do
expect(::Security::SecurityOrchestrationPolicies::CreatePipelineService).to(
receive(:new)
.with(project: project, current_user: current_user, params: { action: policy[:actions].first, branch: 'master' })
.and_call_original)
expect(::Security::SecurityOrchestrationPolicies::CreatePipelineService).to(
receive(:new)
.with(project: project, current_user: current_user, params: { action: policy[:actions].first, branch: 'production' })
.and_call_original)
service.execute(schedule)
end
it 'invokes Security::SecurityOrchestrationPolicies::CreatePipelineService' do
expect(::Security::SecurityOrchestrationPolicies::CreatePipelineService).to receive(:new).twice.and_call_original
service.execute(schedule)
end
end
context 'when policy actions exists and there are multiple matching branches' do context 'when policy actions exists and there are multiple matching branches' do
it 'creates multiple scan pipelines and updates next_run_at' do it 'creates multiple scan pipelines and updates next_run_at' do
expect { service.execute(schedule) }.to change(Ci::Pipeline, :count).by(2) expect { service.execute(schedule) }.to change(Ci::Pipeline, :count).by(2)
......
...@@ -38,11 +38,12 @@ RSpec.describe Security::SecurityOrchestrationPolicies::ScanPipelineService do ...@@ -38,11 +38,12 @@ RSpec.describe Security::SecurityOrchestrationPolicies::ScanPipelineService do
{ scan: 'secret_detection' }, { scan: 'secret_detection' },
{ scan: 'dast', scanner_profile: 'Scanner Profile', site_profile: 'Site Profile' }, { scan: 'dast', scanner_profile: 'Scanner Profile', site_profile: 'Site Profile' },
{ scan: 'cluster_image_scanning' }, { scan: 'cluster_image_scanning' },
{ scan: 'container_scanning' } { scan: 'container_scanning' },
{ scan: 'sast' }
] ]
end end
it_behaves_like 'creates scan jobs', 4, [:'secret-detection-0', :'dast-1', :'cluster-image-scanning-2', :'container-scanning-3'] it_behaves_like 'creates scan jobs', 5, [:'secret-detection-0', :'dast-1', :'cluster-image-scanning-2', :'container-scanning-3', :'sast-4']
end end
context 'when there are valid and invalid actions' do context 'when there are valid and invalid actions' do
......
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