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:
- 'ee/spec/models/project_import_state_spec.rb'
- 'ee/spec/models/push_rule_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/graphql/mutations/dast_on_demand_scans/create_spec.rb'
- 'ee/spec/requests/api/graphql/mutations/dast_site_profiles/delete_spec.rb'
......
......@@ -3,11 +3,10 @@
module Projects
module Security
class ConfigurationPresenter < Gitlab::View::Presenter::Delegated
include Gitlab::Utils::StrongMemoize
include AutoDevopsHelper
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
......@@ -20,14 +19,14 @@ module Projects
features: features,
help_page_path: help_page_path('user/application_security/index'),
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
# 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
gitlab_ci_present: project.repository.gitlab_ci_yml.present?,
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
......@@ -41,12 +40,9 @@ module Projects
private
def autofix_enabled
{
dependency_scanning: project_settings&.auto_fix_dependency_scanning,
container_scanning: project_settings&.auto_fix_container_scanning
}
end
def autofix_enabled; end
def auto_fix_user_path; end
def can_enable_auto_devops?
feature_available?(:builds, current_user) &&
......@@ -54,11 +50,13 @@ module Projects
!archived?
end
def can_toggle_autofix; end
def gitlab_ci_history_path
return '' if project.empty_repo?
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_ci = ::Gitlab::FileDetector::PATTERNS[:gitlab_ci]
::Gitlab::Routing.url_helpers.project_blame_path(project, File.join(project.default_branch_or_main, gitlab_ci))
end
def features
......@@ -78,11 +76,13 @@ module Projects
end
def scan(type, configured: false)
scan = ::Gitlab::Security::ScanConfiguration.new(project: project, type: type, configured: configured)
{
type: type,
configured: configured,
configuration_path: configuration_path(type),
available: feature_available(type)
type: scan.type,
configured: scan.configured?,
configuration_path: scan.configuration_path,
available: scan.available?
}
end
......@@ -93,23 +93,8 @@ module Projects
def project_settings
project.security_setting
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
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
# The record hasn't been loaded yet, so
# hit the database with all pending IDs to prevent N+1
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|
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