Commit da89acd2 authored by Robert Speicher's avatar Robert Speicher

Merge branch 'move_mutation_for_mr_merge' into 'master'

[RUN AS-IF-FOSS] Move all the changes related to reading SAST Configuration to CE

See merge request gitlab-org/gitlab!51169
parents ff1baa6f d7375e97
...@@ -9,13 +9,13 @@ module Types ...@@ -9,13 +9,13 @@ module Types
description 'Represents the analyzers entity in SAST CI configuration' description 'Represents the analyzers entity in SAST CI configuration'
argument :name, GraphQL::STRING_TYPE, required: true, argument :name, GraphQL::STRING_TYPE, required: true,
description: 'Name of analyzer' description: 'Name of analyzer.'
argument :enabled, GraphQL::BOOLEAN_TYPE, required: true, argument :enabled, GraphQL::BOOLEAN_TYPE, required: true,
description: 'State of the analyzer' description: 'State of the analyzer.'
argument :variables, [::Types::CiConfiguration::Sast::EntityInputType], argument :variables, [::Types::CiConfiguration::Sast::EntityInputType],
description: 'List of variables for the analyzer', description: 'List of variables for the analyzer.',
required: false required: false
end end
end end
......
...@@ -9,19 +9,19 @@ module Types ...@@ -9,19 +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, field :variables, ::Types::CiConfiguration::Sast::EntityType.connection_type, null: true,
description: 'List of supported variables' description: 'List of supported variables.'
end end
end end
end end
......
...@@ -9,13 +9,13 @@ module Types ...@@ -9,13 +9,13 @@ module Types
description 'Represents an entity in SAST CI configuration' description 'Represents an entity in SAST CI configuration'
argument :field, GraphQL::STRING_TYPE, required: true, argument :field, GraphQL::STRING_TYPE, required: true,
description: 'CI keyword of entity' description: 'CI keyword of entity.'
argument :default_value, GraphQL::STRING_TYPE, required: true, argument :default_value, GraphQL::STRING_TYPE, required: true,
description: 'Default value that is used if value is empty' description: 'Default value that is used if value is empty.'
argument :value, GraphQL::STRING_TYPE, required: true, argument :value, GraphQL::STRING_TYPE, required: true,
description: 'Current value of the entity' description: 'Current value of the entity.'
end end
end end
end end
......
...@@ -8,15 +8,15 @@ module Types ...@@ -8,15 +8,15 @@ module Types
description 'Represents a CI configuration of SAST' description 'Represents a CI configuration of SAST'
argument :global, [::Types::CiConfiguration::Sast::EntityInputType], argument :global, [::Types::CiConfiguration::Sast::EntityInputType],
description: 'List of global entities related to SAST configuration', description: 'List of global entities related to SAST configuration.',
required: false required: false
argument :pipeline, [::Types::CiConfiguration::Sast::EntityInputType], argument :pipeline, [::Types::CiConfiguration::Sast::EntityInputType],
description: 'List of pipeline entities related to SAST configuration', description: 'List of pipeline entities related to SAST configuration.',
required: false required: false
argument :analyzers, [::Types::CiConfiguration::Sast::AnalyzersEntityInputType], argument :analyzers, [::Types::CiConfiguration::Sast::AnalyzersEntityInputType],
description: 'List of analyzers and related variables for the SAST configuration', description: 'List of analyzers and related variables for the SAST configuration.',
required: false required: false
end end
end end
......
...@@ -16,6 +16,10 @@ module Types ...@@ -16,6 +16,10 @@ module Types
field :path, GraphQL::STRING_TYPE, null: false, field :path, GraphQL::STRING_TYPE, null: false,
description: 'Path of the project' description: 'Path of the project'
field :sast_ci_configuration, Types::CiConfiguration::Sast::Type, null: true,
calls_gitaly: true,
description: 'SAST CI configuration for the project'
field :name_with_namespace, GraphQL::STRING_TYPE, null: false, field :name_with_namespace, GraphQL::STRING_TYPE, null: false,
description: 'Full name of the project with its namespace' description: 'Full name of the project with its namespace'
field :name, GraphQL::STRING_TYPE, null: false, field :name, GraphQL::STRING_TYPE, null: false,
...@@ -359,6 +363,12 @@ module Types ...@@ -359,6 +363,12 @@ module Types
project.container_repositories.size project.container_repositories.size
end end
def sast_ci_configuration
return unless Ability.allowed?(current_user, :download_code, object)
::Security::CiConfiguration::SastParserService.new(object).configuration
end
private private
def project def project
......
...@@ -22102,27 +22102,27 @@ Represents an analyzer entity in SAST CI configuration ...@@ -22102,27 +22102,27 @@ 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 List of supported variables.
""" """
variables( variables(
""" """
...@@ -22187,17 +22187,17 @@ Represents the analyzers entity in SAST CI configuration ...@@ -22187,17 +22187,17 @@ Represents the analyzers entity in SAST CI configuration
""" """
input SastCiConfigurationAnalyzersEntityInput { input SastCiConfigurationAnalyzersEntityInput {
""" """
State of the analyzer State of the analyzer.
""" """
enabled: Boolean! enabled: Boolean!
""" """
Name of analyzer Name of analyzer.
""" """
name: String! name: String!
""" """
List of variables for the analyzer List of variables for the analyzer.
""" """
variables: [SastCiConfigurationEntityInput!] variables: [SastCiConfigurationEntityInput!]
} }
...@@ -22307,17 +22307,17 @@ Represents an entity in SAST CI configuration ...@@ -22307,17 +22307,17 @@ Represents an entity in SAST CI configuration
""" """
input SastCiConfigurationEntityInput { input SastCiConfigurationEntityInput {
""" """
Default value that is used if value is empty Default value that is used if value is empty.
""" """
defaultValue: String! defaultValue: String!
""" """
CI keyword of entity CI keyword of entity.
""" """
field: String! field: String!
""" """
Current value of the entity Current value of the entity.
""" """
value: String! value: String!
} }
...@@ -22327,17 +22327,17 @@ Represents a CI configuration of SAST ...@@ -22327,17 +22327,17 @@ Represents a CI configuration of SAST
""" """
input SastCiConfigurationInput { input SastCiConfigurationInput {
""" """
List of analyzers and related variables for the SAST configuration List of analyzers and related variables for the SAST configuration.
""" """
analyzers: [SastCiConfigurationAnalyzersEntityInput!] analyzers: [SastCiConfigurationAnalyzersEntityInput!]
""" """
List of global entities related to SAST configuration List of global entities related to SAST configuration.
""" """
global: [SastCiConfigurationEntityInput!] global: [SastCiConfigurationEntityInput!]
""" """
List of pipeline entities related to SAST configuration List of pipeline entities related to SAST configuration.
""" """
pipeline: [SastCiConfigurationEntityInput!] pipeline: [SastCiConfigurationEntityInput!]
} }
......
...@@ -63880,7 +63880,7 @@ ...@@ -63880,7 +63880,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": [
], ],
...@@ -63894,7 +63894,7 @@ ...@@ -63894,7 +63894,7 @@
}, },
{ {
"name": "enabled", "name": "enabled",
"description": "Indicates whether an analyzer is enabled", "description": "Indicates whether an analyzer is enabled.",
"args": [ "args": [
], ],
...@@ -63908,7 +63908,7 @@ ...@@ -63908,7 +63908,7 @@
}, },
{ {
"name": "label", "name": "label",
"description": "Analyzer label used in the config UI", "description": "Analyzer label used in the config UI.",
"args": [ "args": [
], ],
...@@ -63922,7 +63922,7 @@ ...@@ -63922,7 +63922,7 @@
}, },
{ {
"name": "name", "name": "name",
"description": "Name of the analyzer", "description": "Name of the analyzer.",
"args": [ "args": [
], ],
...@@ -63936,7 +63936,7 @@ ...@@ -63936,7 +63936,7 @@
}, },
{ {
"name": "variables", "name": "variables",
"description": "List of supported variables", "description": "List of supported variables.",
"args": [ "args": [
{ {
"name": "after", "name": "after",
...@@ -64115,7 +64115,7 @@ ...@@ -64115,7 +64115,7 @@
"inputFields": [ "inputFields": [
{ {
"name": "name", "name": "name",
"description": "Name of analyzer", "description": "Name of analyzer.",
"type": { "type": {
"kind": "NON_NULL", "kind": "NON_NULL",
"name": null, "name": null,
...@@ -64129,7 +64129,7 @@ ...@@ -64129,7 +64129,7 @@
}, },
{ {
"name": "enabled", "name": "enabled",
"description": "State of the analyzer", "description": "State of the analyzer.",
"type": { "type": {
"kind": "NON_NULL", "kind": "NON_NULL",
"name": null, "name": null,
...@@ -64143,7 +64143,7 @@ ...@@ -64143,7 +64143,7 @@
}, },
{ {
"name": "variables", "name": "variables",
"description": "List of variables for the analyzer", "description": "List of variables for the analyzer.",
"type": { "type": {
"kind": "LIST", "kind": "LIST",
"name": null, "name": null,
...@@ -64448,7 +64448,7 @@ ...@@ -64448,7 +64448,7 @@
"inputFields": [ "inputFields": [
{ {
"name": "field", "name": "field",
"description": "CI keyword of entity", "description": "CI keyword of entity.",
"type": { "type": {
"kind": "NON_NULL", "kind": "NON_NULL",
"name": null, "name": null,
...@@ -64462,7 +64462,7 @@ ...@@ -64462,7 +64462,7 @@
}, },
{ {
"name": "defaultValue", "name": "defaultValue",
"description": "Default value that is used if value is empty", "description": "Default value that is used if value is empty.",
"type": { "type": {
"kind": "NON_NULL", "kind": "NON_NULL",
"name": null, "name": null,
...@@ -64476,7 +64476,7 @@ ...@@ -64476,7 +64476,7 @@
}, },
{ {
"name": "value", "name": "value",
"description": "Current value of the entity", "description": "Current value of the entity.",
"type": { "type": {
"kind": "NON_NULL", "kind": "NON_NULL",
"name": null, "name": null,
...@@ -64501,7 +64501,7 @@ ...@@ -64501,7 +64501,7 @@
"inputFields": [ "inputFields": [
{ {
"name": "global", "name": "global",
"description": "List of global entities related to SAST configuration", "description": "List of global entities related to SAST configuration.",
"type": { "type": {
"kind": "LIST", "kind": "LIST",
"name": null, "name": null,
...@@ -64519,7 +64519,7 @@ ...@@ -64519,7 +64519,7 @@
}, },
{ {
"name": "pipeline", "name": "pipeline",
"description": "List of pipeline entities related to SAST configuration", "description": "List of pipeline entities related to SAST configuration.",
"type": { "type": {
"kind": "LIST", "kind": "LIST",
"name": null, "name": null,
...@@ -64537,7 +64537,7 @@ ...@@ -64537,7 +64537,7 @@
}, },
{ {
"name": "analyzers", "name": "analyzers",
"description": "List of analyzers and related variables for the SAST configuration", "description": "List of analyzers and related variables for the SAST configuration.",
"type": { "type": {
"kind": "LIST", "kind": "LIST",
"name": null, "name": null,
...@@ -3183,11 +3183,11 @@ Represents an analyzer entity in SAST CI configuration. ...@@ -3183,11 +3183,11 @@ 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. |
| `variables` | SastCiConfigurationEntityConnection | List of supported variables | | `variables` | SastCiConfigurationEntityConnection | List of supported variables. |
### SastCiConfigurationEntity ### SastCiConfigurationEntity
......
...@@ -15,10 +15,6 @@ module EE ...@@ -15,10 +15,6 @@ module EE
null: true, null: true,
description: 'The DAST scanner profiles associated with the project' description: 'The DAST scanner profiles associated with the project'
field :sast_ci_configuration, ::Types::CiConfiguration::Sast::Type, null: true,
calls_gitaly: true,
description: 'SAST CI configuration for the project'
field :vulnerabilities, field :vulnerabilities,
::Types::VulnerabilityType.connection_type, ::Types::VulnerabilityType.connection_type,
null: true, null: true,
...@@ -131,12 +127,6 @@ module EE ...@@ -131,12 +127,6 @@ module EE
Hash.new(0).merge(object.requirements.counts_by_state) Hash.new(0).merge(object.requirements.counts_by_state)
end end
def sast_ci_configuration
return unless Ability.allowed?(current_user, :download_code, object)
::Security::CiConfiguration::SastParserService.new(object).configuration
end
def security_dashboard_path def security_dashboard_path
Rails.application.routes.url_helpers.project_security_dashboard_index_path(object) Rails.application.routes.url_helpers.project_security_dashboard_index_path(object)
end end
......
---
title: Move all the changes related to Mutation.configureSast to CE
merge_request: 51169
author:
type: changed
...@@ -17,7 +17,7 @@ RSpec.describe GitlabSchema.types['Project'] do ...@@ -17,7 +17,7 @@ RSpec.describe GitlabSchema.types['Project'] do
it 'includes the ee specific fields' do it 'includes the ee specific fields' do
expected_fields = %w[ expected_fields = %w[
vulnerabilities sast_ci_configuration vulnerability_scanners requirement_states_count vulnerabilities vulnerability_scanners requirement_states_count
vulnerability_severities_count packages compliance_frameworks vulnerabilities_count_by_day vulnerability_severities_count packages compliance_frameworks vulnerabilities_count_by_day
security_dashboard_path iterations cluster_agents repository_size_excess actual_repository_size_limit security_dashboard_path iterations cluster_agents repository_size_excess actual_repository_size_limit
code_coverage_summary code_coverage_summary
...@@ -26,160 +26,6 @@ RSpec.describe GitlabSchema.types['Project'] do ...@@ -26,160 +26,6 @@ RSpec.describe GitlabSchema.types['Project'] do
expect(described_class).to include_graphql_fields(*expected_fields) expect(described_class).to include_graphql_fields(*expected_fields)
end end
describe 'sast_ci_configuration' do
include_context 'read ci configuration for sast enabled project'
let(:query) do
%(
query {
project(fullPath: "#{project.full_path}") {
sastCiConfiguration {
global {
nodes {
type
options {
nodes {
label
value
}
}
field
label
defaultValue
value
size
}
}
pipeline {
nodes {
type
options {
nodes {
label
value
}
}
field
label
defaultValue
value
size
}
}
analyzers {
nodes {
name
label
enabled
}
}
}
}
}
)
end
before do
allow(project.repository).to receive(:blob_data_at).and_return(gitlab_ci_yml_content)
end
subject { GitlabSchema.execute(query, context: { current_user: user }).as_json }
it "returns the project's sast configuration for global variables" do
secure_analyzers_prefix = subject.dig('data', 'project', 'sastCiConfiguration', 'global', 'nodes').first
expect(secure_analyzers_prefix['type']).to eq('string')
expect(secure_analyzers_prefix['field']).to eq('SECURE_ANALYZERS_PREFIX')
expect(secure_analyzers_prefix['label']).to eq('Image prefix')
expect(secure_analyzers_prefix['defaultValue']).to eq('registry.gitlab.com/gitlab-org/security-products/analyzers')
expect(secure_analyzers_prefix['value']).to eq('registry.gitlab.com/gitlab-org/security-products/analyzers')
expect(secure_analyzers_prefix['size']).to eq('LARGE')
expect(secure_analyzers_prefix['options']).to be_nil
end
it "returns the project's sast configuration for pipeline variables" do
pipeline_stage = subject.dig('data', 'project', 'sastCiConfiguration', 'pipeline', 'nodes').first
expect(pipeline_stage['type']).to eq('string')
expect(pipeline_stage['field']).to eq('stage')
expect(pipeline_stage['label']).to eq('Stage')
expect(pipeline_stage['defaultValue']).to eq('test')
expect(pipeline_stage['value']).to eq('test')
expect(pipeline_stage['size']).to eq('MEDIUM')
end
it "returns the project's sast configuration for analyzer variables" do
analyzer = subject.dig('data', 'project', 'sastCiConfiguration', 'analyzers', 'nodes').first
expect(analyzer['name']).to eq('brakeman')
expect(analyzer['label']).to eq('Brakeman')
expect(analyzer['enabled']).to eq(true)
end
context "with guest user" do
before do
project.add_guest(user)
end
context 'when project is private' do
let(:project) { create(:project, :private, :repository) }
it "returns no configuration" do
secure_analyzers_prefix = subject.dig('data', 'project', 'sastCiConfiguration')
expect(secure_analyzers_prefix).to be_nil
end
end
context 'when project is public' do
let(:project) { create(:project, :public, :repository) }
context 'when repository is accessible by everyone' do
it "returns the project's sast configuration for global variables" do
secure_analyzers_prefix = subject.dig('data', 'project', 'sastCiConfiguration', 'global', 'nodes').first
expect(secure_analyzers_prefix['type']).to eq('string')
expect(secure_analyzers_prefix['field']).to eq('SECURE_ANALYZERS_PREFIX')
end
end
end
end
context "with non-member user" do
before do
project.team.truncate
end
context 'when project is private' do
let(:project) { create(:project, :private, :repository) }
it "returns no configuration" do
secure_analyzers_prefix = subject.dig('data', 'project', 'sastCiConfiguration')
expect(secure_analyzers_prefix).to be_nil
end
end
context 'when project is public' do
let(:project) { create(:project, :public, :repository) }
context 'when repository is accessible by everyone' do
it "returns the project's sast configuration for global variables" do
secure_analyzers_prefix = subject.dig('data', 'project', 'sastCiConfiguration', 'global', 'nodes').first
expect(secure_analyzers_prefix['type']).to eq('string')
expect(secure_analyzers_prefix['field']).to eq('SECURE_ANALYZERS_PREFIX')
end
end
context 'when repository is accessible only by team members' do
it "returns no configuration" do
project.project_feature.update!(merge_requests_access_level: ProjectFeature::DISABLED,
builds_access_level: ProjectFeature::DISABLED,
repository_access_level: ProjectFeature::PRIVATE)
secure_analyzers_prefix = subject.dig('data', 'project', 'sastCiConfiguration')
expect(secure_analyzers_prefix).to be_nil
end
end
end
end
end
describe 'security_scanners' do describe 'security_scanners' do
let_it_be(:project) { create(:project, :repository) } let_it_be(:project) { create(:project, :repository) }
let_it_be(:pipeline) { create(:ci_pipeline, project: project, sha: project.commit.id, ref: project.default_branch) } let_it_be(:pipeline) { create(:ci_pipeline, project: project, sha: project.commit.id, ref: project.default_branch) }
......
...@@ -5,9 +5,10 @@ module Gitlab ...@@ -5,9 +5,10 @@ module Gitlab
module Template module Template
module Finders module Finders
class GlobalTemplateFinder < BaseTemplateFinder class GlobalTemplateFinder < BaseTemplateFinder
def initialize(base_dir, extension, categories = {}, excluded_patterns: []) def initialize(base_dir, extension, categories = {}, include_categories_for_file = {}, excluded_patterns: [])
@categories = categories @categories = categories
@extension = extension @extension = extension
@include_categories_for_file = include_categories_for_file
@excluded_patterns = excluded_patterns @excluded_patterns = excluded_patterns
super(base_dir) super(base_dir)
...@@ -47,7 +48,9 @@ module Gitlab ...@@ -47,7 +48,9 @@ module Gitlab
end end
def select_directory(file_name) def select_directory(file_name)
@categories.keys.find do |category| categories = @categories
categories.merge!(@include_categories_for_file[file_name]) if @include_categories_for_file[file_name].present?
categories.keys.find do |category|
File.exist?(File.join(category_directory(category), file_name)) File.exist?(File.join(category_directory(category), file_name))
end end
end end
......
...@@ -25,6 +25,12 @@ module Gitlab ...@@ -25,6 +25,12 @@ module Gitlab
} }
end end
def include_categories_for_file
{
"SAST#{self.extension}" => { 'Security' => 'Security' }
}
end
def excluded_patterns def excluded_patterns
strong_memoize(:excluded_patterns) do strong_memoize(:excluded_patterns) do
BASE_EXCLUDED_PATTERNS + additional_excluded_patterns BASE_EXCLUDED_PATTERNS + additional_excluded_patterns
...@@ -41,7 +47,11 @@ module Gitlab ...@@ -41,7 +47,11 @@ module Gitlab
def finder(project = nil) def finder(project = nil)
Gitlab::Template::Finders::GlobalTemplateFinder.new( Gitlab::Template::Finders::GlobalTemplateFinder.new(
self.base_dir, self.extension, self.categories, excluded_patterns: self.excluded_patterns self.base_dir,
self.extension,
self.categories,
self.include_categories_for_file,
excluded_patterns: self.excluded_patterns
) )
end end
end end
......
...@@ -46,11 +46,7 @@ module Security ...@@ -46,11 +46,7 @@ module Security
end end
def collect_analyzer_values(config, key) def collect_analyzer_values(config, key)
analyzer_variables = config['analyzers'] analyzer_variables = analyzer_variables_for(config, key)
&.select {|a| a['enabled'] && a['variables'] }
&.flat_map {|a| a['variables'] }
&.collect {|v| [v['field'], v[key]] }.to_h
analyzer_variables['SAST_EXCLUDED_ANALYZERS'] = if key == 'value' analyzer_variables['SAST_EXCLUDED_ANALYZERS'] = if key == 'value'
config['analyzers'] config['analyzers']
&.reject {|a| a['enabled'] } &.reject {|a| a['enabled'] }
...@@ -64,6 +60,13 @@ module Security ...@@ -64,6 +60,13 @@ module Security
analyzer_variables analyzer_variables
end end
def analyzer_variables_for(config, key)
config['analyzers']
&.select {|a| a['enabled'] && a['variables'] }
&.flat_map {|a| a['variables'] }
&.collect {|v| [v['field'], v[key]] }.to_h
end
def update_existing_content! def update_existing_content!
@existing_gitlab_ci_content['stages'] = set_stages @existing_gitlab_ci_content['stages'] = set_stages
@existing_gitlab_ci_content['variables'] = set_variables(global_variables, @existing_gitlab_ci_content) @existing_gitlab_ci_content['variables'] = set_variables(global_variables, @existing_gitlab_ci_content)
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe GitlabSchema.types['SastCiConfigurationAnalyzersEntityInput'] do RSpec.describe ::Types::CiConfiguration::Sast::AnalyzersEntityInputType do
it { expect(described_class.graphql_name).to eq('SastCiConfigurationAnalyzersEntityInput') } it { expect(described_class.graphql_name).to eq('SastCiConfigurationAnalyzersEntityInput') }
it { expect(described_class.arguments.keys).to match_array(%w[enabled name variables]) } it { expect(described_class.arguments.keys).to match_array(%w[enabled name variables]) }
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe GitlabSchema.types['SastCiConfigurationEntityInput'] do RSpec.describe ::Types::CiConfiguration::Sast::EntityInputType do
it { expect(described_class.graphql_name).to eq('SastCiConfigurationEntityInput') } it { expect(described_class.graphql_name).to eq('SastCiConfigurationEntityInput') }
it { expect(described_class.arguments.keys).to match_array(%w[field defaultValue value]) } it { expect(described_class.arguments.keys).to match_array(%w[field defaultValue value]) }
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe GitlabSchema.types['SastCiConfigurationInput'] do RSpec.describe ::Types::CiConfiguration::Sast::InputType do
it { expect(described_class.graphql_name).to eq('SastCiConfigurationInput') } it { expect(described_class.graphql_name).to eq('SastCiConfigurationInput') }
it { expect(described_class.arguments.keys).to match_array(%w[global pipeline analyzers]) } it { expect(described_class.arguments.keys).to match_array(%w[global pipeline analyzers]) }
......
...@@ -31,12 +31,171 @@ RSpec.describe GitlabSchema.types['Project'] do ...@@ -31,12 +31,171 @@ RSpec.describe GitlabSchema.types['Project'] do
container_expiration_policy service_desk_enabled service_desk_address container_expiration_policy service_desk_enabled service_desk_address
issue_status_counts terraform_states alert_management_integrations issue_status_counts terraform_states alert_management_integrations
container_repositories container_repositories_count container_repositories container_repositories_count
pipeline_analytics squash_read_only pipeline_analytics squash_read_only sast_ci_configuration
] ]
expect(described_class).to include_graphql_fields(*expected_fields) expect(described_class).to include_graphql_fields(*expected_fields)
end end
describe 'sast_ci_configuration' do
let_it_be(:project) { create(:project) }
let_it_be(:user) { create(:user) }
before do
stub_licensed_features(security_dashboard: true)
project.add_developer(user)
allow(project.repository).to receive(:blob_data_at).and_return(gitlab_ci_yml_content)
end
include_context 'read ci configuration for sast enabled project'
let(:query) do
%(
query {
project(fullPath: "#{project.full_path}") {
sastCiConfiguration {
global {
nodes {
type
options {
nodes {
label
value
}
}
field
label
defaultValue
value
size
}
}
pipeline {
nodes {
type
options {
nodes {
label
value
}
}
field
label
defaultValue
value
size
}
}
analyzers {
nodes {
name
label
enabled
}
}
}
}
}
)
end
subject { GitlabSchema.execute(query, context: { current_user: user }).as_json }
it "returns the project's sast configuration for global variables" do
secure_analyzers_prefix = subject.dig('data', 'project', 'sastCiConfiguration', 'global', 'nodes').first
expect(secure_analyzers_prefix['type']).to eq('string')
expect(secure_analyzers_prefix['field']).to eq('SECURE_ANALYZERS_PREFIX')
expect(secure_analyzers_prefix['label']).to eq('Image prefix')
expect(secure_analyzers_prefix['defaultValue']).to eq('registry.gitlab.com/gitlab-org/security-products/analyzers')
expect(secure_analyzers_prefix['value']).to eq('registry.gitlab.com/gitlab-org/security-products/analyzers')
expect(secure_analyzers_prefix['size']).to eq('LARGE')
expect(secure_analyzers_prefix['options']).to be_nil
end
it "returns the project's sast configuration for pipeline variables" do
pipeline_stage = subject.dig('data', 'project', 'sastCiConfiguration', 'pipeline', 'nodes').first
expect(pipeline_stage['type']).to eq('string')
expect(pipeline_stage['field']).to eq('stage')
expect(pipeline_stage['label']).to eq('Stage')
expect(pipeline_stage['defaultValue']).to eq('test')
expect(pipeline_stage['value']).to eq('test')
expect(pipeline_stage['size']).to eq('MEDIUM')
end
it "returns the project's sast configuration for analyzer variables" do
analyzer = subject.dig('data', 'project', 'sastCiConfiguration', 'analyzers', 'nodes').first
expect(analyzer['name']).to eq('brakeman')
expect(analyzer['label']).to eq('Brakeman')
expect(analyzer['enabled']).to eq(true)
end
context "with guest user" do
before do
project.add_guest(user)
end
context 'when project is private' do
let(:project) { create(:project, :private, :repository) }
it "returns no configuration" do
secure_analyzers_prefix = subject.dig('data', 'project', 'sastCiConfiguration')
expect(secure_analyzers_prefix).to be_nil
end
end
context 'when project is public' do
let(:project) { create(:project, :public, :repository) }
context 'when repository is accessible by everyone' do
it "returns the project's sast configuration for global variables" do
secure_analyzers_prefix = subject.dig('data', 'project', 'sastCiConfiguration', 'global', 'nodes').first
expect(secure_analyzers_prefix['type']).to eq('string')
expect(secure_analyzers_prefix['field']).to eq('SECURE_ANALYZERS_PREFIX')
end
end
end
end
context "with non-member user" do
before do
project.team.truncate
end
context 'when project is private' do
let(:project) { create(:project, :private, :repository) }
it "returns no configuration" do
secure_analyzers_prefix = subject.dig('data', 'project', 'sastCiConfiguration')
expect(secure_analyzers_prefix).to be_nil
end
end
context 'when project is public' do
let(:project) { create(:project, :public, :repository) }
context 'when repository is accessible by everyone' do
it "returns the project's sast configuration for global variables" do
secure_analyzers_prefix = subject.dig('data', 'project', 'sastCiConfiguration', 'global', 'nodes').first
expect(secure_analyzers_prefix['type']).to eq('string')
expect(secure_analyzers_prefix['field']).to eq('SECURE_ANALYZERS_PREFIX')
end
end
context 'when repository is accessible only by team members' do
it "returns no configuration" do
project.project_feature.update!(merge_requests_access_level: ProjectFeature::DISABLED,
builds_access_level: ProjectFeature::DISABLED,
repository_access_level: ProjectFeature::PRIVATE)
secure_analyzers_prefix = subject.dig('data', 'project', 'sastCiConfiguration')
expect(secure_analyzers_prefix).to be_nil
end
end
end
end
end
describe 'issue field' do describe 'issue field' do
subject { described_class.fields['issue'] } subject { described_class.fields['issue'] }
......
...@@ -15,9 +15,19 @@ RSpec.describe Gitlab::Template::Finders::GlobalTemplateFinder do ...@@ -15,9 +15,19 @@ RSpec.describe Gitlab::Template::Finders::GlobalTemplateFinder do
FileUtils.rm_rf(base_dir) FileUtils.rm_rf(base_dir)
end end
subject(:finder) { described_class.new(base_dir, '', { 'General' => '', 'Bar' => 'Bar' }, excluded_patterns: excluded_patterns) } subject(:finder) do
described_class.new(base_dir, '',
{ 'General' => '', 'Bar' => 'Bar' },
include_categories_for_file,
excluded_patterns: excluded_patterns)
end
let(:excluded_patterns) { [] } let(:excluded_patterns) { [] }
let(:include_categories_for_file) do
{
"SAST" => { "Security" => "Security" }
}
end
describe '.find' do describe '.find' do
context 'with a non-prefixed General template' do context 'with a non-prefixed General template' do
...@@ -60,6 +70,7 @@ RSpec.describe Gitlab::Template::Finders::GlobalTemplateFinder do ...@@ -60,6 +70,7 @@ RSpec.describe Gitlab::Template::Finders::GlobalTemplateFinder do
context 'with a prefixed template' do context 'with a prefixed template' do
before do before do
create_template!('Bar/test-template') create_template!('Bar/test-template')
create_template!('Security/SAST')
end end
it 'finds the template with a prefix' do it 'finds the template with a prefix' do
...@@ -76,6 +87,16 @@ RSpec.describe Gitlab::Template::Finders::GlobalTemplateFinder do ...@@ -76,6 +87,16 @@ RSpec.describe Gitlab::Template::Finders::GlobalTemplateFinder do
expect { finder.find('../foo') }.to raise_error(/Invalid path/) expect { finder.find('../foo') }.to raise_error(/Invalid path/)
end end
context 'with include_categories_for_file being present' do
it 'finds the template with a prefix' do
expect(finder.find('SAST')).to be_present
end
it 'does not find any template which is missing in include_categories_for_file' do
expect(finder.find('DAST')).to be_nil
end
end
context 'while listed as an exclusion' do context 'while listed as an exclusion' do
let(:excluded_patterns) { [%r{^Bar/test-template$}] } let(:excluded_patterns) { [%r{^Bar/test-template$}] }
......
# frozen_string_literal: true # frozen_string_literal: true
require 'fast_spec_helper' require 'spec_helper'
RSpec.describe Security::CiConfiguration::SastBuildActions do RSpec.describe Security::CiConfiguration::SastBuildActions do
let(:default_sast_values) do let(:default_sast_values) do
...@@ -308,7 +308,9 @@ RSpec.describe Security::CiConfiguration::SastBuildActions do ...@@ -308,7 +308,9 @@ RSpec.describe Security::CiConfiguration::SastBuildActions do
subject(:result) { described_class.new(auto_devops_enabled, params, gitlab_ci_content).generate } subject(:result) { described_class.new(auto_devops_enabled, params, gitlab_ci_content).generate }
before do before do
allow_any_instance_of(described_class).to receive(:auto_devops_stages).and_return(fast_auto_devops_stages) allow_next_instance_of(described_class) do |sast_build_actions|
allow(sast_build_actions).to receive(:auto_devops_stages).and_return(fast_auto_devops_stages)
end
end end
it 'generates the correct YML' do it 'generates the correct YML' 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