Commit e3b580f5 authored by rossfuhrman's avatar rossfuhrman Committed by James Fargher

Expose analyzer info for SAST Config

This MR exposes wether an analyzer should be enabled or not, as well as
exposes variables specific to some of those analyzers. See
https://gitlab.com/gitlab-org/gitlab/-/issues/235880
and
https://gitlab.com/gitlab-org/gitlab/-/issues/235878
parent aadcc4ac
...@@ -52,67 +52,126 @@ ...@@ -52,67 +52,126 @@
{ {
"name": "brakeman", "name": "brakeman",
"label": "Brakeman", "label": "Brakeman",
"enabled" : true "enabled" : true,
"description": "Ruby on Rails",
"variables": [
{
"field" : "SAST_BRAKEMAN_LEVEL",
"label" : "Brakeman confidence level.",
"type": "string",
"default_value": "1",
"value": "",
"size": "SMALL",
"description": "Ignore Brakeman vulnerabilities under given confidence level. Integer, 1=Low, 2=Medium, 3=High."
}
]
}, },
{ {
"name": "bandit", "name": "bandit",
"label": "Bandit", "label": "Bandit",
"enabled" : true "enabled" : true,
"description": "Python",
"variables": [
{
"field" : "SAST_BANDIT_EXCLUDED_PATHS",
"label" : "Paths to exclude from scan.",
"type": "string",
"default_value": "",
"value": "",
"size": "SMALL",
"description": "Comma-separated list of paths to exclude from scan. Uses Python’s 'fnmatch' syntax; For example: '*/tests/*, */venv/*'"
}
]
}, },
{ {
"name": "eslint", "name": "eslint",
"label": "ESLint", "label": "ESLint",
"enabled" : true "enabled" : true,
"description": "JavaScript, TypeScript, React",
"variables": []
}, },
{ {
"name": "flawfinder", "name": "flawfinder",
"label": "Flawfinder", "label": "Flawfinder",
"enabled" : true "enabled" : true,
"description": "C, C++",
"variables": [
{
"field" : "SAST_FLAWFINDER_LEVEL",
"label" : "Flawfinder risk level",
"type": "string",
"default_value": "1",
"value": "",
"size": "SMALL",
"description": "Ignore Flawfinder vulnerabilities under given risk level. Integer, 0=No risk, 5=High risk."
}
]
}, },
{ {
"name": "kubesec", "name": "kubesec",
"label": "kubesec", "label": "kubesec",
"enabled" : true "enabled" : true,
"description": "Kubernetes manifests, Helm Charts",
"variables": []
}, },
{ {
"name": "nodejsscan", "name": "nodejs-scan",
"label": "Node.js Scan", "label": "Node.js Scan",
"enabled" : true "enabled" : true,
"description": "Node.js",
"variables": []
}, },
{ {
"name": "gosec", "name": "gosec",
"label": "Golang Security Checker", "label": "Golang Security Checker",
"enabled" : true "enabled" : true,
"description": "Go",
"variables": [
{
"field" : "SAST_GOSEC_LEVEL",
"label" : "Gosec confidence level",
"type": "string",
"default_value": "0",
"value": "",
"size": "SMALL",
"description": "Ignore Gosec vulnerabilities under given confidence level. Integer, 0=Undefined, 1=Low, 2=Medium, 3=High."
}
]
}, },
{ {
"name": "phpcs-security-audit", "name": "phpcs-security-audit",
"label": "PHP Security Audit", "label": "PHP Security Audit",
"enabled" : true "enabled" : true,
"description": "PHP",
"variables": []
}, },
{ {
"name": "pmd-apex", "name": "pmd-apex",
"label": "PMD APEX", "label": "PMD APEX",
"enabled" : true "enabled" : true,
"description": "Apex (Salesforce)",
"variables": []
}, },
{ {
"name": "security-code-scan", "name": "security-code-scan",
"label": "Security Code Scan", "label": "Security Code Scan",
"enabled" : true "enabled" : true,
"description": ".NET Core, .NET Framework",
"variables": []
}, },
{ {
"name": "sobelow", "name": "sobelow",
"label": "Sobelow", "label": "Sobelow",
"enabled" : true "enabled" : true,
"description": "Elixir (Phoenix)",
"variables": []
}, },
{ {
"name": "spotbugs", "name": "spotbugs",
"label": "Spotbugs", "label": "Spotbugs",
"enabled" : true "enabled" : true,
}, "description": "Groovy, Java, Scala",
{ "variables": []
"name": "secrets",
"label": "Secrets",
"enabled" : true
} }
] ]
} }
...@@ -15161,24 +15161,49 @@ Represents an analyzer entity in SAST CI configuration ...@@ -15161,24 +15161,49 @@ Represents an analyzer entity in SAST CI configuration
""" """
type SastCiConfigurationAnalyzersEntity { type SastCiConfigurationAnalyzersEntity {
""" """
Analyzer description that is displayed on the form. Analyzer description that is displayed on the form
""" """
description: String description: String
""" """
Indicates whether an analyzer is enabled. Indicates whether an analyzer is enabled
""" """
enabled: Boolean enabled: Boolean
""" """
Analyzer label used in the config UI. Analyzer label used in the config UI
""" """
label: String label: String
""" """
Name of the analyzer. Name of the analyzer
""" """
name: String name: String
"""
List of supported variables
"""
variables(
"""
Returns the elements in the list that come after the specified cursor.
"""
after: String
"""
Returns the elements in the list that come before the specified cursor.
"""
before: String
"""
Returns the first _n_ elements from the list.
"""
first: Int
"""
Returns the last _n_ elements from the list.
"""
last: Int
): SastCiConfigurationEntityConnection
} }
""" """
......
...@@ -44128,6 +44128,59 @@ ...@@ -44128,6 +44128,59 @@
}, },
"isDeprecated": false, "isDeprecated": false,
"deprecationReason": null "deprecationReason": null
},
{
"name": "variables",
"description": "List of supported variables",
"args": [
{
"name": "after",
"description": "Returns the elements in the list that come after the specified cursor.",
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"defaultValue": null
},
{
"name": "before",
"description": "Returns the elements in the list that come before the specified cursor.",
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"defaultValue": null
},
{
"name": "first",
"description": "Returns the first _n_ elements from the list.",
"type": {
"kind": "SCALAR",
"name": "Int",
"ofType": null
},
"defaultValue": null
},
{
"name": "last",
"description": "Returns the last _n_ elements from the list.",
"type": {
"kind": "SCALAR",
"name": "Int",
"ofType": null
},
"defaultValue": null
}
],
"type": {
"kind": "OBJECT",
"name": "SastCiConfigurationEntityConnection",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
} }
], ],
"inputFields": null, "inputFields": null,
...@@ -44144,7 +44197,7 @@ ...@@ -44144,7 +44197,7 @@
"fields": [ "fields": [
{ {
"name": "description", "name": "description",
"description": "Analyzer description that is displayed on the form.", "description": "Analyzer description that is displayed on the form",
"args": [ "args": [
], ],
...@@ -44158,7 +44211,7 @@ ...@@ -44158,7 +44211,7 @@
}, },
{ {
"name": "enabled", "name": "enabled",
"description": "Indicates whether an analyzer is enabled.", "description": "Indicates whether an analyzer is enabled",
"args": [ "args": [
], ],
...@@ -44172,7 +44225,7 @@ ...@@ -44172,7 +44225,7 @@
}, },
{ {
"name": "label", "name": "label",
"description": "Analyzer label used in the config UI.", "description": "Analyzer label used in the config UI",
"args": [ "args": [
], ],
...@@ -44186,7 +44239,7 @@ ...@@ -44186,7 +44239,7 @@
}, },
{ {
"name": "name", "name": "name",
"description": "Name of the analyzer.", "description": "Name of the analyzer",
"args": [ "args": [
], ],
...@@ -2104,10 +2104,10 @@ Represents an analyzer entity in SAST CI configuration ...@@ -2104,10 +2104,10 @@ Represents an analyzer entity in SAST CI configuration
| Field | Type | Description | | Field | Type | Description |
| ----- | ---- | ----------- | | ----- | ---- | ----------- |
| `description` | String | Analyzer description that is displayed on the form. | | `description` | String | Analyzer description that is displayed on the form |
| `enabled` | Boolean | Indicates whether an analyzer is enabled. | | `enabled` | Boolean | Indicates whether an analyzer is enabled |
| `label` | String | Analyzer label used in the config UI. | | `label` | String | Analyzer label used in the config UI |
| `name` | String | Name of the analyzer. | | `name` | String | Name of the analyzer |
### SastCiConfigurationEntity ### SastCiConfigurationEntity
......
...@@ -9,16 +9,19 @@ module Types ...@@ -9,16 +9,19 @@ module Types
description 'Represents an analyzer entity in SAST CI configuration' description 'Represents an analyzer entity in SAST CI configuration'
field :name, GraphQL::STRING_TYPE, null: true, field :name, GraphQL::STRING_TYPE, null: true,
description: 'Name of the analyzer.' description: 'Name of the analyzer'
field :label, GraphQL::STRING_TYPE, null: true, field :label, GraphQL::STRING_TYPE, null: true,
description: 'Analyzer label used in the config UI.' description: 'Analyzer label used in the config UI'
field :enabled, GraphQL::BOOLEAN_TYPE, null: true, field :enabled, GraphQL::BOOLEAN_TYPE, null: true,
description: 'Indicates whether an analyzer is enabled.' description: 'Indicates whether an analyzer is enabled'
field :description, GraphQL::STRING_TYPE, null: true, field :description, GraphQL::STRING_TYPE, null: true,
description: 'Analyzer description that is displayed on the form.' description: 'Analyzer description that is displayed on the form'
field :variables, ::Types::CiConfiguration::Sast::EntityType.connection_type, null: true,
description: 'List of supported variables'
end end
end end
end end
......
...@@ -19,6 +19,10 @@ module Security ...@@ -19,6 +19,10 @@ module Security
fill_current_value_with_default_for(result, :pipeline) fill_current_value_with_default_for(result, :pipeline)
populate_current_value_for(result, :global) populate_current_value_for(result, :global)
populate_current_value_for(result, :pipeline) populate_current_value_for(result, :pipeline)
fill_current_value_with_default_for_analyzers(result)
populate_current_value_for_analyzers(result)
result result
end end
...@@ -46,10 +50,29 @@ module Security ...@@ -46,10 +50,29 @@ module Security
end end
end end
def fill_current_value_with_default_for_analyzers(result)
result[:analyzers].each do |analyzer|
analyzer[:variables].each do |entity|
entity[:value] = entity[:default_value] if entity[:default_value]
end
end
end
def populate_current_value_for_analyzers(result)
result[:analyzers].each do |analyzer|
analyzer[:enabled] = sast_default_analyzers.include?(analyzer[:name])
populate_current_value_for(analyzer, :variables)
end
end
def sast_template_attributes def sast_template_attributes
@sast_template_attributes ||= build_sast_attributes(sast_template_content) @sast_template_attributes ||= build_sast_attributes(sast_template_content)
end end
def sast_default_analyzers
@sast_default_analyzers ||= gitlab_ci_yml_attributes["SAST_DEFAULT_ANALYZERS"] || sast_template_attributes["SAST_DEFAULT_ANALYZERS"]
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: Expose analyzer info for SAST Config
merge_request: 41825
author:
type: added
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe GitlabSchema.types['SastCiConfigurationAnalyzersEntity'] do RSpec.describe GitlabSchema.types['SastCiConfigurationAnalyzersEntity'] do
let(:fields) { %i[name label enabled description] } let(:fields) { %i[name label enabled description variables] }
it { expect(described_class.graphql_name).to eq('SastCiConfigurationAnalyzersEntity') } it { expect(described_class.graphql_name).to eq('SastCiConfigurationAnalyzersEntity') }
......
...@@ -12,6 +12,8 @@ RSpec.describe Security::CiConfiguration::SastParserService do ...@@ -12,6 +12,8 @@ RSpec.describe Security::CiConfiguration::SastParserService do
let(:sast_analyzer_image_tag) { configuration['global'][2] } let(:sast_analyzer_image_tag) { configuration['global'][2] }
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(:sast_brakeman_level) { brakeman['variables'][0] }
it 'parses the configuration for SAST' do it 'parses the configuration for SAST' do
expect(secure_analyzers_prefix['default_value']).to eql('registry.gitlab.com/gitlab-org/security-products/analyzers') expect(secure_analyzers_prefix['default_value']).to eql('registry.gitlab.com/gitlab-org/security-products/analyzers')
...@@ -19,6 +21,8 @@ RSpec.describe Security::CiConfiguration::SastParserService do ...@@ -19,6 +21,8 @@ RSpec.describe Security::CiConfiguration::SastParserService do
expect(sast_analyzer_image_tag['default_value']).to eql('2') expect(sast_analyzer_image_tag['default_value']).to eql('2')
expect(sast_pipeline_stage['default_value']).to eql('test') expect(sast_pipeline_stage['default_value']).to eql('test')
expect(sast_search_max_depth['default_value']).to eql('4') expect(sast_search_max_depth['default_value']).to eql('4')
expect(brakeman['enabled']).to be(true)
expect(sast_brakeman_level['default_value']).to eql('1')
end end
context 'while populating current values of the entities' do context 'while populating current values of the entities' do
...@@ -30,6 +34,8 @@ RSpec.describe Security::CiConfiguration::SastParserService do ...@@ -30,6 +34,8 @@ RSpec.describe Security::CiConfiguration::SastParserService do
expect(sast_analyzer_image_tag['value']).to eql('2') expect(sast_analyzer_image_tag['value']).to eql('2')
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(sast_brakeman_level['value']).to eql('2')
end end
end end
...@@ -41,6 +47,8 @@ RSpec.describe Security::CiConfiguration::SastParserService do ...@@ -41,6 +47,8 @@ RSpec.describe Security::CiConfiguration::SastParserService do
expect(sast_analyzer_image_tag['value']).to eql('2') expect(sast_analyzer_image_tag['value']).to eql('2')
expect(sast_pipeline_stage['value']).to eql('test') expect(sast_pipeline_stage['value']).to eql('test')
expect(sast_search_max_depth['value']).to eql('4') expect(sast_search_max_depth['value']).to eql('4')
expect(brakeman['enabled']).to be(true)
expect(sast_brakeman_level['value']).to eql('1')
end end
end end
end end
......
...@@ -4,6 +4,7 @@ include: ...@@ -4,6 +4,7 @@ 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"
stages: stages:
- our_custom_security_stage - our_custom_security_stage
...@@ -11,3 +12,4 @@ sast: ...@@ -11,3 +12,4 @@ sast:
stage: our_custom_security_stage stage: our_custom_security_stage
variables: variables:
SEARCH_MAX_DEPTH: 8 SEARCH_MAX_DEPTH: 8
SAST_BRAKEMAN_LEVEL: 2
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