Commit 49da15c8 authored by Matthias Käppler's avatar Matthias Käppler

Merge branch '342135-move-presenters' into 'master'

Move Security ConfigurationPresenter to FOSS

See merge request gitlab-org/gitlab!72631
parents 8bd8557c 5f17c0e6
...@@ -468,7 +468,6 @@ RSpec/AnyInstanceOf: ...@@ -468,7 +468,6 @@ RSpec/AnyInstanceOf:
- 'ee/spec/models/project_import_state_spec.rb' - 'ee/spec/models/project_import_state_spec.rb'
- 'ee/spec/models/push_rule_spec.rb' - 'ee/spec/models/push_rule_spec.rb'
- 'ee/spec/presenters/ci/pipeline_presenter_spec.rb' - 'ee/spec/presenters/ci/pipeline_presenter_spec.rb'
- 'ee/spec/presenters/projects/security/configuration_presenter_spec.rb'
- 'ee/spec/requests/api/geo_nodes_spec.rb' - 'ee/spec/requests/api/geo_nodes_spec.rb'
- 'ee/spec/requests/api/graphql/mutations/dast_on_demand_scans/create_spec.rb' - 'ee/spec/requests/api/graphql/mutations/dast_on_demand_scans/create_spec.rb'
- 'ee/spec/requests/api/graphql/mutations/dast_site_profiles/delete_spec.rb' - 'ee/spec/requests/api/graphql/mutations/dast_site_profiles/delete_spec.rb'
......
...@@ -3,11 +3,10 @@ ...@@ -3,11 +3,10 @@
module Projects module Projects
module Security module Security
class ConfigurationPresenter < Gitlab::View::Presenter::Delegated class ConfigurationPresenter < Gitlab::View::Presenter::Delegated
include Gitlab::Utils::StrongMemoize
include AutoDevopsHelper include AutoDevopsHelper
include ::Security::LatestPipelineInformation include ::Security::LatestPipelineInformation
delegator_override_with Gitlab::Utils::StrongMemoize # TODO: Remove `Gitlab::Utils::StrongMemoize` inclusion as it's duplicate delegator_override_with Gitlab::Utils::StrongMemoize
presents ::Project, as: :project presents ::Project, as: :project
...@@ -20,14 +19,14 @@ module Projects ...@@ -20,14 +19,14 @@ module Projects
features: features, features: features,
help_page_path: help_page_path('user/application_security/index'), help_page_path: help_page_path('user/application_security/index'),
latest_pipeline_path: latest_pipeline_path, latest_pipeline_path: latest_pipeline_path,
auto_fix_enabled: autofix_enabled,
can_toggle_auto_fix_settings: auto_fix_permission,
# TODO: gitlab_ci_present will incorrectly report `false` if the CI/CD configuration file name # TODO: gitlab_ci_present will incorrectly report `false` if the CI/CD configuration file name
# has been customized and a file with the given custom name exists in the repo. This edge case # has been customized and a file with the given custom name exists in the repo. This edge case
# will be addressed in https://gitlab.com/gitlab-org/gitlab/-/issues/342465 # will be addressed in https://gitlab.com/gitlab-org/gitlab/-/issues/342465
gitlab_ci_present: project.repository.gitlab_ci_yml.present?, gitlab_ci_present: project.repository.gitlab_ci_yml.present?,
gitlab_ci_history_path: gitlab_ci_history_path, gitlab_ci_history_path: gitlab_ci_history_path,
auto_fix_user_path: '/' # TODO: real link will be updated with https://gitlab.com/gitlab-org/gitlab/-/issues/215669 auto_fix_enabled: autofix_enabled,
can_toggle_auto_fix_settings: can_toggle_autofix,
auto_fix_user_path: auto_fix_user_path
} }
end end
...@@ -41,12 +40,9 @@ module Projects ...@@ -41,12 +40,9 @@ module Projects
private private
def autofix_enabled def autofix_enabled; end
{
dependency_scanning: project_settings&.auto_fix_dependency_scanning, def auto_fix_user_path; end
container_scanning: project_settings&.auto_fix_container_scanning
}
end
def can_enable_auto_devops? def can_enable_auto_devops?
feature_available?(:builds, current_user) && feature_available?(:builds, current_user) &&
...@@ -54,11 +50,13 @@ module Projects ...@@ -54,11 +50,13 @@ module Projects
!archived? !archived?
end end
def can_toggle_autofix; end
def gitlab_ci_history_path def gitlab_ci_history_path
return '' if project.empty_repo? return '' if project.empty_repo?
gitlab_ci = Gitlab::FileDetector::PATTERNS[:gitlab_ci] gitlab_ci = ::Gitlab::FileDetector::PATTERNS[:gitlab_ci]
Gitlab::Routing.url_helpers.project_blame_path(project, File.join(project.default_branch_or_main, gitlab_ci)) ::Gitlab::Routing.url_helpers.project_blame_path(project, File.join(project.default_branch_or_main, gitlab_ci))
end end
def features def features
...@@ -78,11 +76,13 @@ module Projects ...@@ -78,11 +76,13 @@ module Projects
end end
def scan(type, configured: false) def scan(type, configured: false)
scan = ::Gitlab::Security::ScanConfiguration.new(project: project, type: type, configured: configured)
{ {
type: type, type: scan.type,
configured: configured, configured: scan.configured?,
configuration_path: configuration_path(type), configuration_path: scan.configuration_path,
available: feature_available(type) available: scan.available?
} }
end end
...@@ -93,23 +93,8 @@ module Projects ...@@ -93,23 +93,8 @@ module Projects
def project_settings def project_settings
project.security_setting project.security_setting
end end
def configuration_path(type)
{
sast: project_security_configuration_sast_path(project),
dast: project_security_configuration_dast_path(project),
dast_profiles: project_security_configuration_dast_scans_path(project),
api_fuzzing: project_security_configuration_api_fuzzing_path(project),
corpus_management: (project_security_configuration_corpus_management_path(project) if ::Feature.enabled?(:corpus_management, project, default_enabled: :yaml) && scanner_enabled?(:coverage_fuzzing))
}[type]
end
def feature_available(type)
# SAST and Secret Detection are always available, but this isn't
# reflected by our license model yet.
# TODO: https://gitlab.com/gitlab-org/gitlab/-/issues/333113
%w[sast secret_detection].include?(type) || project.licensed_feature_available?(type)
end
end end
end end
end end
Projects::Security::ConfigurationPresenter.prepend_mod_with('Projects::Security::ConfigurationPresenter')
# frozen_string_literal: true
module EE
module Projects
module Security
module ConfigurationPresenter
private
def can_toggle_autofix
try(:auto_fix_permission)
end
def autofix_enabled
{
dependency_scanning: project_settings&.auto_fix_dependency_scanning,
container_scanning: project_settings&.auto_fix_container_scanning
}
end
def auto_fix_user_path
'/' # TODO: real link will be updated with https://gitlab.com/gitlab-org/gitlab/-/issues/215669
end
end
end
end
end
# frozen_string_literal: true
module EE
module Gitlab
module Security
module ScanConfiguration
def available?
super || project.licensed_feature_available?(type)
end
def configured?
configured
end
def configuration_path
configurable_scans[type] if available? || type == :corpus_management
end
private
def configurable_scans
strong_memoize(:configurable_scans) do
{
dast: project_security_configuration_dast_path(project),
dast_profiles: project_security_configuration_dast_scans_path(project),
api_fuzzing: project_security_configuration_api_fuzzing_path(project),
corpus_management: (project_security_configuration_corpus_management_path(project) if ::Feature.enabled?(:corpus_management, project, default_enabled: :yaml))
}.merge(super)
end
end
end
end
end
end
...@@ -39,7 +39,7 @@ module Gitlab ...@@ -39,7 +39,7 @@ module Gitlab
# The record hasn't been loaded yet, so # The record hasn't been loaded yet, so
# hit the database with all pending IDs to prevent N+1 # hit the database with all pending IDs to prevent N+1
profiles_by_project_id = @lazy_state[:dast_pending_profiles].group_by(&:project_id) profiles_by_project_id = @lazy_state[:dast_pending_profiles].group_by(&:project_id)
policy_configurations = Security::OrchestrationPolicyConfiguration.for_project(profiles_by_project_id.keys).index_by(&:project_id) policy_configurations = ::Security::OrchestrationPolicyConfiguration.for_project(profiles_by_project_id.keys).index_by(&:project_id)
profiles_by_project_id.each do |project_id, dast_pending_profiles| profiles_by_project_id.each do |project_id, dast_pending_profiles|
dast_pending_profiles.each do |profile| dast_pending_profiles.each do |profile|
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe ::Gitlab::Security::ScanConfiguration do
let_it_be(:project) { create(:project, :repository) }
let(:scan) { described_class.new(project: project, type: type, configured: configured) }
describe '#available?' do
subject { scan.available? }
let(:configured) { true }
context 'with a core scanner' do
let(:type) { :sast }
before do
stub_licensed_features(sast: false)
end
it { is_expected.to be_truthy }
end
context 'with licensed scanner that is available' do
let(:type) { :api_fuzzing }
before do
stub_licensed_features(api_fuzzing: true)
end
it { is_expected.to be_truthy }
end
context 'with licensed scanner that is not available' do
let(:type) { :api_fuzzing }
before do
stub_licensed_features(api_fuzzing: false)
end
it { is_expected.to be_falsey }
end
context 'with custom scanner' do
let(:type) { :my_scanner }
it { is_expected.to be_falsey }
end
end
describe '#configuration_path' do
subject { scan.configuration_path }
let(:configured) { true }
context 'with licensed scanner' do
let(:type) { :dast }
let(:configuration_path) { "/#{project.namespace.path}/#{project.name}/-/security/configuration/dast" }
before do
stub_licensed_features(dast: true)
end
it { is_expected.to eq(configuration_path) }
end
context 'with a scanner under feature flag' do
let(:type) { :corpus_management }
let(:configuration_path) { "/#{project.namespace.path}/#{project.name}/-/security/configuration/corpus_management" }
it { is_expected.to eq(configuration_path) }
context 'when feature flag is disabled' do
before do
stub_feature_flags(corpus_management: false)
end
it { is_expected.to be_nil }
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Projects::Security::ConfigurationPresenter do
include Gitlab::Routing.url_helpers
let_it_be(:project) { create(:project, :repository) }
let_it_be(:current_user) { create(:user) }
describe '#to_h' do
subject(:result) { described_class.new(project, auto_fix_permission: true, current_user: current_user).to_h }
it 'includes settings for auto_fix feature' do
auto_fix = result[:auto_fix_enabled]
expect(auto_fix[:dependency_scanning]).to be_truthy
expect(auto_fix[:container_scanning]).to be_truthy
end
it 'reports auto_fix permissions' do
expect(result[:can_toggle_auto_fix_settings]).to be_truthy
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Projects::Security::ConfigurationPresenter do
include Gitlab::Routing.url_helpers
let(:project) { create(:project, :repository) }
let(:project_with_no_repo) { create(:project) }
let(:current_user) { create(:user) }
it 'presents the given project' do
presenter = described_class.new(project)
expect(presenter.id).to be(project.id)
end
before do
project.add_maintainer(current_user)
stub_licensed_features(licensed_scan_types.to_h { |type| [type, true] })
end
describe '#to_h' do
subject { described_class.new(project, auto_fix_permission: true, current_user: current_user).to_html_data_attribute }
it 'includes links to auto devops and secure product docs' do
expect(subject[:auto_devops_help_page_path]).to eq(help_page_path('topics/autodevops/index'))
expect(subject[:help_page_path]).to eq(help_page_path('user/application_security/index'))
end
it 'includes settings for auto_fix feature' do
auto_fix = Gitlab::Json.parse(subject[:auto_fix_enabled])
expect(auto_fix['dependency_scanning']).to be_truthy
expect(auto_fix['container_scanning']).to be_truthy
end
it 'includes the path to gitlab_ci history' do
expect(subject[:gitlab_ci_history_path]).to eq(project_blame_path(project, 'master/.gitlab-ci.yml'))
end
context 'when the project is empty' do
subject { described_class.new(project_with_no_repo, auto_fix_permission: true, current_user: current_user).to_html_data_attribute }
it 'includes a blank gitlab_ci history path' do
expect(subject[:gitlab_ci_history_path]).to eq('')
end
end
context 'when the project has no default branch set' do
before do
allow(project).to receive(:default_branch).and_return(nil)
end
it 'includes the path to gitlab_ci history' do
expect(subject[:gitlab_ci_history_path]).to eq(project_blame_path(project, 'master/.gitlab-ci.yml'))
end
end
context "when the latest default branch pipeline's source is auto devops" do
before do
pipeline = create(
:ci_pipeline,
:auto_devops_source,
project: project,
ref: project.default_branch,
sha: project.commit.sha
)
create(:ci_build, :sast, pipeline: pipeline, status: 'success')
create(:ci_build, :dast, pipeline: pipeline, status: 'success')
create(:ci_build, :secret_detection, pipeline: pipeline, status: 'pending')
end
it 'reports that auto devops is enabled' do
expect(subject[:auto_devops_enabled]).to be_truthy
end
it 'reports auto_fix permissions' do
expect(subject[:can_toggle_auto_fix_settings]).to be_truthy
end
it 'reports that all scanners are configured for which latest pipeline has builds' do
expect(Gitlab::Json.parse(subject[:features])).to contain_exactly(
security_scan(:dast, configured: true),
security_scan(:sast, configured: true),
security_scan(:sast_iac, configured: false),
security_scan(:container_scanning, configured: false),
security_scan(:cluster_image_scanning, configured: false),
security_scan(:dependency_scanning, configured: false),
security_scan(:license_scanning, configured: false),
security_scan(:secret_detection, configured: true),
security_scan(:coverage_fuzzing, configured: false),
security_scan(:api_fuzzing, configured: false),
security_scan(:dast_profiles, configured: true),
security_scan(:corpus_management, configured: true)
)
end
end
context "when coverage fuzzing has run in a pipeline with feature flag off" do
before do
stub_feature_flags(corpus_management: false)
pipeline = create(
:ci_pipeline,
:auto_devops_source,
project: project,
ref: project.default_branch,
sha: project.commit.sha
)
create(:ci_build, :coverage_fuzzing, pipeline: pipeline, status: 'success')
end
it 'reports that coverage fuzzing, corpus management, and DAST are configured' do
expect(Gitlab::Json.parse(subject[:features])).to contain_exactly(
security_scan(:dast, configured: false),
security_scan(:sast, configured: false),
security_scan(:sast_iac, configured: false),
security_scan(:container_scanning, configured: false),
security_scan(:cluster_image_scanning, configured: false),
security_scan(:dependency_scanning, configured: false),
security_scan(:license_scanning, configured: false),
security_scan(:secret_detection, configured: false),
security_scan(:coverage_fuzzing, configured: true),
security_scan(:api_fuzzing, configured: false),
security_scan(:dast_profiles, configured: true),
security_scan(:corpus_management, configured: true)
)
end
end
context "when coverage fuzzing has run in a pipeline with feature flag on" do
before do
stub_feature_flags(corpus_management: true)
pipeline = create(
:ci_pipeline,
:auto_devops_source,
project: project,
ref: project.default_branch,
sha: project.commit.sha
)
create(:ci_build, :coverage_fuzzing, pipeline: pipeline, status: 'success')
end
it 'reports that coverage fuzzing, corpus management, and DAST are configured' do
expect(Gitlab::Json.parse(subject[:features])).to contain_exactly(
security_scan(:dast, configured: false),
security_scan(:sast, configured: false),
security_scan(:sast_iac, configured: false),
security_scan(:container_scanning, configured: false),
security_scan(:cluster_image_scanning, configured: false),
security_scan(:dependency_scanning, configured: false),
security_scan(:license_scanning, configured: false),
security_scan(:secret_detection, configured: false),
security_scan(:coverage_fuzzing, configured: true),
security_scan(:api_fuzzing, configured: false),
security_scan(:dast_profiles, configured: true),
security_scan(:corpus_management, configured: true, configuration_path: project_security_configuration_corpus_management_path(project))
)
end
end
context 'when the project has no default branch pipeline' do
it 'reports that auto devops is disabled' do
expect(subject[:auto_devops_enabled]).to be_falsy
end
it 'includes a link to CI pipeline docs' do
expect(subject[:latest_pipeline_path]).to eq(help_page_path('ci/pipelines'))
end
it 'reports all security jobs as unconfigured' do
expect(Gitlab::Json.parse(subject[:features])).to contain_exactly(
security_scan(:dast, configured: false),
security_scan(:sast, configured: false),
security_scan(:sast_iac, configured: false),
security_scan(:container_scanning, configured: false),
security_scan(:cluster_image_scanning, configured: false),
security_scan(:dependency_scanning, configured: false),
security_scan(:license_scanning, configured: false),
security_scan(:secret_detection, configured: false),
security_scan(:coverage_fuzzing, configured: false),
security_scan(:api_fuzzing, configured: false),
security_scan(:dast_profiles, configured: true),
security_scan(:corpus_management, configured: true)
)
end
end
context 'when latest default branch pipeline`s source is not auto devops' do
let(:pipeline) do
create(
:ci_pipeline,
project: project,
ref: project.default_branch,
sha: project.commit.sha
)
end
before do
create(:ci_build, :sast, pipeline: pipeline)
create(:ci_build, :dast, pipeline: pipeline)
create(:ci_build, :secret_detection, pipeline: pipeline)
end
it 'uses the latest default branch pipeline to determine whether a security job is configured' do
expect(Gitlab::Json.parse(subject[:features])).to contain_exactly(
security_scan(:dast, configured: true),
security_scan(:dast_profiles, configured: true),
security_scan(:sast, configured: true),
security_scan(:sast_iac, configured: false),
security_scan(:container_scanning, configured: false),
security_scan(:cluster_image_scanning, configured: false),
security_scan(:dependency_scanning, configured: false),
security_scan(:license_scanning, configured: false),
security_scan(:secret_detection, configured: true),
security_scan(:coverage_fuzzing, configured: false),
security_scan(:api_fuzzing, configured: false),
security_scan(:corpus_management, configured: true)
)
end
it 'detects security jobs even when the job has more than one report' do
config = { artifacts: { reports: { other_job: ['gl-other-report.json'], sast: ['gl-sast-report.json'] } } }
complicated_job = build_stubbed(:ci_build, options: config)
allow_next_instance_of(::Security::SecurityJobsFinder) do |finder|
allow(finder).to receive(:execute).and_return([complicated_job])
end
subject
expect(Gitlab::Json.parse(subject[:features])).to contain_exactly(
security_scan(:dast, configured: false),
security_scan(:dast_profiles, configured: true),
security_scan(:sast, configured: true),
security_scan(:sast_iac, configured: false),
security_scan(:container_scanning, configured: false),
security_scan(:cluster_image_scanning, configured: false),
security_scan(:dependency_scanning, configured: false),
security_scan(:license_scanning, configured: false),
security_scan(:secret_detection, configured: false),
security_scan(:coverage_fuzzing, configured: false),
security_scan(:api_fuzzing, configured: false),
security_scan(:corpus_management, configured: true)
)
end
it 'detect new license compliance job' do
create(:ci_build, :license_scanning, pipeline: pipeline)
expect(Gitlab::Json.parse(subject[:features])).to contain_exactly(
security_scan(:dast, configured: true),
security_scan(:dast_profiles, configured: true),
security_scan(:sast, configured: true),
security_scan(:sast_iac, configured: false),
security_scan(:container_scanning, configured: false),
security_scan(:cluster_image_scanning, configured: false),
security_scan(:dependency_scanning, configured: false),
security_scan(:license_scanning, configured: true),
security_scan(:secret_detection, configured: true),
security_scan(:coverage_fuzzing, configured: false),
security_scan(:api_fuzzing, configured: false),
security_scan(:corpus_management, configured: true)
)
end
it 'includes a link to the latest pipeline' do
expect(subject[:latest_pipeline_path]).to eq(project_pipeline_path(project, pipeline))
end
context "while retrieving information about gitlab ci file" do
context 'when a .gitlab-ci.yml file exists' do
before do
project.repository.create_file(
project.creator,
Gitlab::FileDetector::PATTERNS[:gitlab_ci],
'contents go here',
message: 'test',
branch_name: 'master')
end
it 'expects gitlab_ci_present to be true' do
expect(subject[:gitlab_ci_present]).to eq(true)
end
end
context 'when a .gitlab-ci.yml file does not exist' do
it 'expects gitlab_ci_present to be false if the file is not present' do
expect(subject[:gitlab_ci_present]).to eq(false)
end
end
end
it 'includes the auto_devops_path' do
expect(subject[:auto_devops_path]).to eq(project_settings_ci_cd_path(project, anchor: 'autodevops-settings'))
end
context "while retrieving information about user's ability to enable auto_devops" do
using RSpec::Parameterized::TableSyntax
where(:is_admin, :archived, :feature_available, :result) do
true | true | true | false
false | true | true | false
true | false | true | true
false | false | true | false
true | true | false | false
false | true | false | false
true | false | false | false
false | false | false | false
end
with_them do
before do
allow_any_instance_of(described_class).to receive(:can?).and_return(is_admin)
allow_any_instance_of(described_class).to receive(:archived?).and_return(archived)
allow_any_instance_of(described_class).to receive(:feature_available?).and_return(feature_available)
end
it 'includes can_enable_auto_devops' do
expect(subject[:can_enable_auto_devops]).to eq(result)
end
end
end
end
end
def security_scan(type, configured:, configuration_path: nil)
path = configuration_path || configuration_path(type)
{
"type" => type.to_s,
"configured" => configured,
"configuration_path" => path,
"available" => licensed_scan_types.include?(type)
}
end
def configuration_path(type)
{
dast: project_security_configuration_dast_path(project),
dast_profiles: project_security_configuration_dast_scans_path(project),
sast: project_security_configuration_sast_path(project),
api_fuzzing: project_security_configuration_api_fuzzing_path(project),
corpus_management: nil
}[type]
end
def licensed_scan_types
::Security::SecurityJobsFinder.allowed_job_types + ::Security::LicenseComplianceJobsFinder.allowed_job_types - [:cluster_image_scanning]
end
end
# frozen_string_literal: true
module Gitlab
module Security
class ScanConfiguration
include ::Gitlab::Utils::StrongMemoize
include Gitlab::Routing.url_helpers
attr_reader :type
def initialize(project:, type:, configured: false)
@project = project
@type = type
@configured = configured
end
def available?
# SAST and Secret Detection are always available, but this isn't
# reflected by our license model yet.
# TODO: https://gitlab.com/gitlab-org/gitlab/-/issues/333113
%i[sast secret_detection].include?(type)
end
def configured?
configured
end
def configuration_path
configurable_scans[type]
end
private
attr_reader :project, :configured
def configurable_scans
strong_memoize(:configurable_scans) do
{
sast: project_security_configuration_sast_path(project)
}
end
end
end
end
end
Gitlab::Security::ScanConfiguration.prepend_mod_with('Gitlab::Security::ScanConfiguration')
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe ::Gitlab::Security::ScanConfiguration do
let_it_be(:project) { create(:project, :repository) }
let(:scan) { described_class.new(project: project, type: type, configured: configured) }
describe '#available?' do
subject { scan.available? }
let(:configured) { true }
context 'with a core scanner' do
let(:type) { :sast }
it { is_expected.to be_truthy }
end
context 'with custom scanner' do
let(:type) { :my_scanner }
it { is_expected.to be_falsey }
end
end
describe '#configured?' do
subject { scan.configured? }
let(:type) { :sast }
let(:configured) { false }
it { is_expected.to be_falsey }
end
describe '#configuration_path' do
subject { scan.configuration_path }
let(:configured) { true }
context 'with a non configurable scaner' do
let(:type) { :secret_detection }
it { is_expected.to be_nil }
end
context 'with licensed scanner for FOSS environment' do
let(:type) { :dast }
before do
stub_env('FOSS_ONLY', '1')
end
it { is_expected.to be_nil }
end
context 'with custom scanner' do
let(:type) { :my_scanner }
it { is_expected.to be_nil }
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Projects::Security::ConfigurationPresenter do
include Gitlab::Routing.url_helpers
using RSpec::Parameterized::TableSyntax
let(:project_with_repo) { create(:project, :repository) }
let(:project_with_no_repo) { create(:project) }
let(:current_user) { create(:user) }
let(:presenter) { described_class.new(project, current_user: current_user) }
before do
stub_licensed_features(licensed_scan_types.to_h { |type| [type, true] })
stub_feature_flags(corpus_management: false)
end
describe '#to_html_data_attribute' do
subject(:html_data) { presenter.to_html_data_attribute }
context 'when latest default branch pipeline`s source is not auto devops' do
let(:project) { project_with_repo }
let(:pipeline) do
create(
:ci_pipeline,
project: project,
ref: project.default_branch,
sha: project.commit.sha
)
end
let!(:build_sast) { create(:ci_build, :sast, pipeline: pipeline) }
let!(:build_dast) { create(:ci_build, :dast, pipeline: pipeline) }
let!(:build_license_scanning) { create(:ci_build, :license_scanning, pipeline: pipeline) }
it 'includes links to auto devops and secure product docs' do
expect(html_data[:auto_devops_help_page_path]).to eq(help_page_path('topics/autodevops/index'))
expect(html_data[:help_page_path]).to eq(help_page_path('user/application_security/index'))
end
it 'returns info that Auto DevOps is not enabled' do
expect(html_data[:auto_devops_enabled]).to eq(false)
expect(html_data[:auto_devops_path]).to eq(project_settings_ci_cd_path(project, anchor: 'autodevops-settings'))
end
it 'includes a link to the latest pipeline' do
expect(html_data[:latest_pipeline_path]).to eq(project_pipeline_path(project, pipeline))
end
it 'has stubs for autofix' do
expect(html_data.keys).to include(:can_toggle_auto_fix_settings, :auto_fix_enabled, :auto_fix_user_path)
end
context "while retrieving information about user's ability to enable auto_devops" do
where(:is_admin, :archived, :feature_available, :result) do
true | true | true | false
false | true | true | false
true | false | true | true
false | false | true | false
true | true | false | false
false | true | false | false
true | false | false | false
false | false | false | false
end
with_them do
before do
allow_next_instance_of(described_class) do |presenter|
allow(presenter).to receive(:can?).and_return(is_admin)
allow(presenter).to receive(:archived?).and_return(archived)
allow(presenter).to receive(:feature_available?).and_return(feature_available)
end
end
it 'includes can_enable_auto_devops' do
expect(html_data[:can_enable_auto_devops]).to eq(result)
end
end
end
it 'includes feature information' do
feature = Gitlab::Json.parse(html_data[:features]).find { |scan| scan['type'] == 'sast' }
expect(feature['type']).to eq('sast')
expect(feature['configured']).to eq(true)
expect(feature['configuration_path']).to eq(project_security_configuration_sast_path(project))
expect(feature['available']).to eq(true)
end
context 'when checking features configured status' do
let(:features) { Gitlab::Json.parse(html_data[:features]) }
where(:type, :configured) do
:dast | true
:dast_profiles | true
:sast | true
:sast_iac | false
:container_scanning | false
:cluster_image_scanning | false
:dependency_scanning | false
:license_scanning | true
:secret_detection | false
:coverage_fuzzing | false
:api_fuzzing | false
:corpus_management | true
end
with_them do
it 'returns proper configuration status' do
feature = features.find { |scan| scan['type'] == type.to_s }
expect(feature['configured']).to eq(configured)
end
end
end
context 'when the job has more than one report' do
let(:features) { Gitlab::Json.parse(html_data[:features]) }
let!(:artifacts) do
{ artifacts: { reports: { other_job: ['gl-other-report.json'], sast: ['gl-sast-report.json'] } } }
end
let!(:complicated_job) { build_stubbed(:ci_build, options: artifacts) }
before do
allow_next_instance_of(::Security::SecurityJobsFinder) do |finder|
allow(finder).to receive(:execute).and_return([complicated_job])
end
end
where(:type, :configured) do
:dast | false
:dast_profiles | true
:sast | true
:sast_iac | false
:container_scanning | false
:cluster_image_scanning | false
:dependency_scanning | false
:license_scanning | true
:secret_detection | false
:coverage_fuzzing | false
:api_fuzzing | false
:corpus_management | true
end
with_them do
it 'properly detects security jobs' do
feature = features.find { |scan| scan['type'] == type.to_s }
expect(feature['configured']).to eq(configured)
end
end
end
it 'includes a link to the latest pipeline' do
expect(subject[:latest_pipeline_path]).to eq(project_pipeline_path(project, pipeline))
end
context "while retrieving information about gitlab ci file" do
context 'when a .gitlab-ci.yml file exists' do
let!(:ci_config) do
project.repository.create_file(
project.creator,
Gitlab::FileDetector::PATTERNS[:gitlab_ci],
'contents go here',
message: 'test',
branch_name: 'master')
end
it 'expects gitlab_ci_present to be true' do
expect(html_data[:gitlab_ci_present]).to eq(true)
end
end
context 'when a .gitlab-ci.yml file does not exist' do
it 'expects gitlab_ci_present to be false if the file is not present' do
expect(html_data[:gitlab_ci_present]).to eq(false)
end
end
end
it 'includes the path to gitlab_ci history' do
expect(subject[:gitlab_ci_history_path]).to eq(project_blame_path(project, 'master/.gitlab-ci.yml'))
end
end
context 'when the project is empty' do
let(:project) { project_with_no_repo }
it 'includes a blank gitlab_ci history path' do
expect(html_data[:gitlab_ci_history_path]).to eq('')
end
end
context 'when the project has no default branch set' do
let(:project) { project_with_repo }
it 'includes the path to gitlab_ci history' do
allow(project).to receive(:default_branch).and_return(nil)
expect(html_data[:gitlab_ci_history_path]).to eq(project_blame_path(project, 'master/.gitlab-ci.yml'))
end
end
context "when the latest default branch pipeline's source is auto devops" do
let(:project) { project_with_repo }
let(:pipeline) do
create(
:ci_pipeline,
:auto_devops_source,
project: project,
ref: project.default_branch,
sha: project.commit.sha
)
end
let!(:build_sast) { create(:ci_build, :sast, pipeline: pipeline, status: 'success') }
let!(:build_dast) { create(:ci_build, :dast, pipeline: pipeline, status: 'success') }
let!(:ci_build) { create(:ci_build, :secret_detection, pipeline: pipeline, status: 'pending') }
it 'reports that auto devops is enabled' do
expect(html_data[:auto_devops_enabled]).to be_truthy
end
context 'when gathering feature data' do
let(:features) { Gitlab::Json.parse(html_data[:features]) }
where(:type, :configured) do
:dast | true
:dast_profiles | true
:sast | true
:sast_iac | false
:container_scanning | false
:cluster_image_scanning | false
:dependency_scanning | false
:license_scanning | false
:secret_detection | true
:coverage_fuzzing | false
:api_fuzzing | false
:corpus_management | true
end
with_them do
it 'reports that all scanners are configured for which latest pipeline has builds' do
feature = features.find { |scan| scan['type'] == type.to_s }
expect(feature['configured']).to eq(configured)
end
end
end
end
context 'when the project has no default branch pipeline' do
let(:project) { project_with_repo }
it 'reports that auto devops is disabled' do
expect(html_data[:auto_devops_enabled]).to be_falsy
end
it 'includes a link to CI pipeline docs' do
expect(html_data[:latest_pipeline_path]).to eq(help_page_path('ci/pipelines'))
end
context 'when gathering feature data' do
let(:features) { Gitlab::Json.parse(html_data[:features]) }
where(:type, :configured) do
:dast | false
:dast_profiles | true
:sast | false
:sast_iac | false
:container_scanning | false
:cluster_image_scanning | false
:dependency_scanning | false
:license_scanning | false
:secret_detection | false
:coverage_fuzzing | false
:api_fuzzing | false
:corpus_management | true
end
with_them do
it 'reports all security jobs as unconfigured with exception of "fake" jobs' do
feature = features.find { |scan| scan['type'] == type.to_s }
expect(feature['configured']).to eq(configured)
end
end
end
end
def licensed_scan_types
::Security::SecurityJobsFinder.allowed_job_types + ::Security::LicenseComplianceJobsFinder.allowed_job_types - [:cluster_image_scanning]
end
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