Commit 5f17c0e6 authored by Tetiana Chupryna's avatar Tetiana Chupryna Committed by Matthias Käppler

Move Security ConfigurationPresenter to FOSS

As SAST and SecretDetection features are moved to GitLab Free
We need to migrate some parts of the codebase to FOSS.
This MR move ConfigurationPresenter and related code.
That enable us to create proper security configuration
for GitLab Free users.

Issue: https://gitlab.com/gitlab-org/gitlab/-/issues/342135
parent 6f84455c
...@@ -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
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
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