Commit 12cc3fee authored by Philip Cunningham's avatar Philip Cunningham Committed by Dylan Griffith

Centralise feature flag checking of on-demand DAST

Switches feature flag over to new policy with additional checks.
parent 2bd832e5
...@@ -21,11 +21,10 @@ module Mutations ...@@ -21,11 +21,10 @@ module Mutations
required: true, required: true,
description: 'ID of the site profile to be used for the scan.' description: 'ID of the site profile to be used for the scan.'
authorize :run_ondemand_dast_scan authorize :create_on_demand_dast_scan
def resolve(full_path:, dast_site_profile_id:) def resolve(full_path:, dast_site_profile_id:)
project = authorized_find!(full_path: full_path) project = authorized_find!(full_path: full_path)
raise_resource_not_available_error! unless Feature.enabled?(:security_on_demand_scans_feature_flag, project, default_enabled: true)
dast_site_profile = find_dast_site_profile(project: project, dast_site_profile_id: dast_site_profile_id) dast_site_profile = find_dast_site_profile(project: project, dast_site_profile_id: dast_site_profile_id)
dast_site = dast_site_profile.dast_site dast_site = dast_site_profile.dast_site
......
...@@ -27,11 +27,10 @@ module Mutations ...@@ -27,11 +27,10 @@ module Mutations
required: false, required: false,
description: 'The maximum number of seconds allowed for the site under test to respond to a request.' description: 'The maximum number of seconds allowed for the site under test to respond to a request.'
authorize :run_ondemand_dast_scan authorize :create_on_demand_dast_scan
def resolve(full_path:, profile_name:, spider_timeout: nil, target_timeout: nil) def resolve(full_path:, profile_name:, spider_timeout: nil, target_timeout: nil)
project = authorized_find!(full_path: full_path) project = authorized_find!(full_path: full_path)
raise_resource_not_available_error! unless Feature.enabled?(:security_on_demand_scans_feature_flag, project, default_enabled: true)
service = ::DastScannerProfiles::CreateService.new(project, current_user) service = ::DastScannerProfiles::CreateService.new(project, current_user)
result = service.execute(name: profile_name, spider_timeout: spider_timeout, target_timeout: target_timeout) result = service.execute(name: profile_name, spider_timeout: spider_timeout, target_timeout: target_timeout)
......
...@@ -23,11 +23,10 @@ module Mutations ...@@ -23,11 +23,10 @@ module Mutations
required: false, required: false,
description: 'The URL of the target to be scanned.' description: 'The URL of the target to be scanned.'
authorize :run_ondemand_dast_scan authorize :create_on_demand_dast_scan
def resolve(full_path:, profile_name:, target_url: nil) def resolve(full_path:, profile_name:, target_url: nil)
project = authorized_find!(full_path: full_path) project = authorized_find!(full_path: full_path)
raise_resource_not_available_error! unless Feature.enabled?(:security_on_demand_scans_feature_flag, project, default_enabled: true)
service = ::DastSiteProfiles::CreateService.new(project, current_user) service = ::DastSiteProfiles::CreateService.new(project, current_user)
result = service.execute(name: profile_name, target_url: target_url) result = service.execute(name: profile_name, target_url: target_url)
......
...@@ -15,13 +15,12 @@ module Mutations ...@@ -15,13 +15,12 @@ module Mutations
required: true, required: true,
description: 'ID of the site profile to be deleted.' description: 'ID of the site profile to be deleted.'
authorize :run_ondemand_dast_scan authorize :create_on_demand_dast_scan
def resolve(full_path:, id:) def resolve(full_path:, id:)
project = authorized_find!(full_path: full_path) project = authorized_find!(full_path: full_path)
raise_resource_not_available_error! unless Feature.enabled?(:security_on_demand_scans_feature_flag, project, default_enabled: true)
dast_site_profile = find_dast_site_profile(project: project, global_id: id) dast_site_profile = find_dast_site_profile(project: project, global_id: id)
return { errors: dast_site_profile.errors.full_messages } unless dast_site_profile.destroy return { errors: dast_site_profile.errors.full_messages } unless dast_site_profile.destroy
{ errors: [] } { errors: [] }
......
...@@ -27,11 +27,10 @@ module Mutations ...@@ -27,11 +27,10 @@ module Mutations
required: false, required: false,
description: 'The URL of the target to be scanned.' description: 'The URL of the target to be scanned.'
authorize :run_ondemand_dast_scan authorize :create_on_demand_dast_scan
def resolve(full_path:, **service_args) def resolve(full_path:, **service_args)
project = authorized_find!(full_path: full_path) project = authorized_find!(full_path: full_path)
raise_resource_not_available_error! unless Feature.enabled?(:security_on_demand_scans_feature_flag, project, default_enabled: true)
service = ::DastSiteProfiles::UpdateService.new(project, current_user) service = ::DastSiteProfiles::UpdateService.new(project, current_user)
result = service.execute(service_args) result = service.execute(service_args)
......
...@@ -27,11 +27,10 @@ module Mutations ...@@ -27,11 +27,10 @@ module Mutations
required: true, required: true,
description: 'The type of scan to be run.' description: 'The type of scan to be run.'
authorize :run_ondemand_dast_scan authorize :create_on_demand_dast_scan
def resolve(project_path:, target_url:, branch:, scan_type:) def resolve(project_path:, target_url:, branch:, scan_type:)
project = authorized_find!(full_path: project_path) project = authorized_find!(full_path: project_path)
raise_resource_not_available_error! unless Feature.enabled?(:security_on_demand_scans_feature_flag, project, default_enabled: true)
service = Ci::RunDastScanService.new(project, current_user) service = Ci::RunDastScanService.new(project, current_user)
result = service.execute(branch: branch, target_url: target_url) result = service.execute(branch: branch, target_url: target_url)
......
...@@ -5,7 +5,7 @@ module Types ...@@ -5,7 +5,7 @@ module Types
graphql_name 'DastScannerProfile' graphql_name 'DastScannerProfile'
description 'Represents a DAST scanner profile.' description 'Represents a DAST scanner profile.'
authorize :run_ondemand_dast_scan authorize :create_on_demand_dast_scan
field :id, GraphQL::ID_TYPE, null: false, field :id, GraphQL::ID_TYPE, null: false,
description: 'ID of the DAST scanner profile' description: 'ID of the DAST scanner profile'
......
...@@ -219,7 +219,6 @@ module EE ...@@ -219,7 +219,6 @@ module EE
enable :admin_feature_flag enable :admin_feature_flag
enable :admin_feature_flags_user_lists enable :admin_feature_flags_user_lists
enable :read_ci_minutes_quota enable :read_ci_minutes_quota
enable :run_ondemand_dast_scan
end end
rule { can?(:developer_access) & iterations_available }.policy do rule { can?(:developer_access) & iterations_available }.policy do
......
...@@ -29,7 +29,7 @@ module Ci ...@@ -29,7 +29,7 @@ module Ci
private private
def allowed? def allowed?
Ability.allowed?(current_user, :run_ondemand_dast_scan, project) Ability.allowed?(current_user, :create_on_demand_dast_scan, project)
end end
def ci_yaml(target_url) def ci_yaml(target_url)
......
...@@ -19,7 +19,7 @@ module DastScannerProfiles ...@@ -19,7 +19,7 @@ module DastScannerProfiles
private private
def allowed? def allowed?
Ability.allowed?(current_user, :run_ondemand_dast_scan, project) Ability.allowed?(current_user, :create_on_demand_dast_scan, project)
end end
end end
end end
...@@ -20,7 +20,7 @@ module DastSiteProfiles ...@@ -20,7 +20,7 @@ module DastSiteProfiles
private private
def allowed? def allowed?
Ability.allowed?(current_user, :run_ondemand_dast_scan, project) Ability.allowed?(current_user, :create_on_demand_dast_scan, project)
end end
end end
end end
...@@ -25,7 +25,7 @@ module DastSiteProfiles ...@@ -25,7 +25,7 @@ module DastSiteProfiles
private private
def allowed? def allowed?
Ability.allowed?(current_user, :run_ondemand_dast_scan, project) Ability.allowed?(current_user, :create_on_demand_dast_scan, project)
end end
# rubocop: disable CodeReuse/ActiveRecord # rubocop: disable CodeReuse/ActiveRecord
......
...@@ -13,7 +13,7 @@ module DastSites ...@@ -13,7 +13,7 @@ module DastSites
private private
def allowed? def allowed?
Ability.allowed?(current_user, :run_ondemand_dast_scan, project) Ability.allowed?(current_user, :create_on_demand_dast_scan, project)
end end
def find_or_create_by!(url) def find_or_create_by!(url)
......
...@@ -12,6 +12,10 @@ RSpec.describe Mutations::DastOnDemandScans::Create do ...@@ -12,6 +12,10 @@ RSpec.describe Mutations::DastOnDemandScans::Create do
subject(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) } subject(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) }
before do
stub_licensed_features(security_on_demand_scans: true)
end
describe '#resolve' do describe '#resolve' do
subject do subject do
mutation.resolve( mutation.resolve(
...@@ -105,6 +109,14 @@ RSpec.describe Mutations::DastOnDemandScans::Create do ...@@ -105,6 +109,14 @@ RSpec.describe Mutations::DastOnDemandScans::Create do
expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable) expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
end end
end end
context 'when on demand scan licensed feature is not available' do
it 'raises an exception' do
stub_licensed_features(security_on_demand_scans: false)
expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
end
end
end end
end end
end end
......
...@@ -12,6 +12,10 @@ RSpec.describe Mutations::DastScannerProfiles::Create do ...@@ -12,6 +12,10 @@ RSpec.describe Mutations::DastScannerProfiles::Create do
subject(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) } subject(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) }
before do
stub_licensed_features(security_on_demand_scans: true)
end
describe '#resolve' do describe '#resolve' do
subject do subject do
mutation.resolve( mutation.resolve(
...@@ -75,6 +79,14 @@ RSpec.describe Mutations::DastScannerProfiles::Create do ...@@ -75,6 +79,14 @@ RSpec.describe Mutations::DastScannerProfiles::Create do
expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable) expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
end end
end end
context 'when on demand scan licensed feature is not available' do
it 'raises an exception' do
stub_licensed_features(security_on_demand_scans: false)
expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
end
end
end end
end end
end end
...@@ -13,6 +13,10 @@ RSpec.describe Mutations::DastSiteProfiles::Create do ...@@ -13,6 +13,10 @@ RSpec.describe Mutations::DastSiteProfiles::Create do
subject(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) } subject(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) }
before do
stub_licensed_features(security_on_demand_scans: true)
end
describe '#resolve' do describe '#resolve' do
subject do subject do
mutation.resolve( mutation.resolve(
...@@ -22,17 +26,7 @@ RSpec.describe Mutations::DastSiteProfiles::Create do ...@@ -22,17 +26,7 @@ RSpec.describe Mutations::DastSiteProfiles::Create do
) )
end end
context 'when on demand scan feature is not enabled' do
it 'raises an exception' do
expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
end
end
context 'when on demand scan feature is enabled' do context 'when on demand scan feature is enabled' do
before do
stub_feature_flags(security_on_demand_scans_feature_flag: true)
end
context 'when the project does not exist' do context 'when the project does not exist' do
let(:full_path) { SecureRandom.hex } let(:full_path) { SecureRandom.hex }
...@@ -63,7 +57,7 @@ RSpec.describe Mutations::DastSiteProfiles::Create do ...@@ -63,7 +57,7 @@ RSpec.describe Mutations::DastSiteProfiles::Create do
end end
end end
context 'when the user is a developer' do context 'when the user can run a dast scan' do
before do before do
project.add_developer(user) project.add_developer(user)
end end
...@@ -95,6 +89,22 @@ RSpec.describe Mutations::DastSiteProfiles::Create do ...@@ -95,6 +89,22 @@ RSpec.describe Mutations::DastSiteProfiles::Create do
expect(response[:errors]).to include('Name has already been taken') expect(response[:errors]).to include('Name has already been taken')
end end
end end
context 'when on demand scan feature is not enabled' do
it 'raises an exception' do
stub_feature_flags(security_on_demand_scans_feature_flag: false)
expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
end
end
context 'when on demand scan licensed feature is not available' do
it 'raises an exception' do
stub_licensed_features(security_on_demand_scans: false)
expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
end
end
end end
end end
end end
......
...@@ -11,6 +11,10 @@ RSpec.describe Mutations::DastSiteProfiles::Delete do ...@@ -11,6 +11,10 @@ RSpec.describe Mutations::DastSiteProfiles::Delete do
subject(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) } subject(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) }
before do
stub_licensed_features(security_on_demand_scans: true)
end
describe '#resolve' do describe '#resolve' do
subject do subject do
mutation.resolve( mutation.resolve(
...@@ -100,6 +104,14 @@ RSpec.describe Mutations::DastSiteProfiles::Delete do ...@@ -100,6 +104,14 @@ RSpec.describe Mutations::DastSiteProfiles::Delete do
expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable) expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
end end
end end
context 'when on demand scan licensed feature is not available' do
it 'raises an exception' do
stub_licensed_features(security_on_demand_scans: false)
expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
end
end
end end
end end
end end
......
...@@ -14,6 +14,10 @@ RSpec.describe Mutations::DastSiteProfiles::Update do ...@@ -14,6 +14,10 @@ RSpec.describe Mutations::DastSiteProfiles::Update do
subject(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) } subject(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) }
before do
stub_licensed_features(security_on_demand_scans: true)
end
describe '#resolve' do describe '#resolve' do
subject do subject do
mutation.resolve( mutation.resolve(
...@@ -100,6 +104,14 @@ RSpec.describe Mutations::DastSiteProfiles::Update do ...@@ -100,6 +104,14 @@ RSpec.describe Mutations::DastSiteProfiles::Update do
expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable) expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
end end
end end
context 'when on demand scan licensed feature is not available' do
it 'raises an exception' do
stub_licensed_features(security_on_demand_scans: false)
expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
end
end
end end
end end
end end
......
...@@ -13,6 +13,10 @@ RSpec.describe Mutations::Pipelines::RunDastScan do ...@@ -13,6 +13,10 @@ RSpec.describe Mutations::Pipelines::RunDastScan do
subject(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) } subject(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) }
before do
stub_licensed_features(security_on_demand_scans: true)
end
describe '#resolve' do describe '#resolve' do
subject do subject do
mutation.resolve( mutation.resolve(
......
...@@ -27,7 +27,7 @@ RSpec.describe GitlabSchema.types['DastScannerProfile'] do ...@@ -27,7 +27,7 @@ RSpec.describe GitlabSchema.types['DastScannerProfile'] do
end end
specify { expect(described_class.graphql_name).to eq('DastScannerProfile') } specify { expect(described_class.graphql_name).to eq('DastScannerProfile') }
specify { expect(described_class).to require_graphql_authorizations(:run_ondemand_dast_scan) } specify { expect(described_class).to require_graphql_authorizations(:create_on_demand_dast_scan) }
it { expect(described_class).to have_graphql_fields(fields) } it { expect(described_class).to have_graphql_fields(fields) }
......
...@@ -5,44 +5,19 @@ require 'spec_helper' ...@@ -5,44 +5,19 @@ require 'spec_helper'
RSpec.describe 'Running a DAST Scan' do RSpec.describe 'Running a DAST Scan' do
include GraphqlHelpers include GraphqlHelpers
let(:project) { create(:project, :repository, creator: current_user) }
let(:current_user) { create(:user) }
let(:full_path) { project.full_path }
let(:dast_site_profile) { create(:dast_site_profile, project: project) } let(:dast_site_profile) { create(:dast_site_profile, project: project) }
let(:mutation_name) { :dast_on_demand_scan_create }
let(:mutation) do let(:mutation) do
graphql_mutation( graphql_mutation(
:dast_on_demand_scan_create, mutation_name,
full_path: full_path, full_path: full_path,
dast_site_profile_id: dast_site_profile.to_global_id.to_s dast_site_profile_id: dast_site_profile.to_global_id.to_s
) )
end end
def mutation_response it_behaves_like 'an on-demand scan mutation when user cannot run an on-demand scan'
graphql_mutation_response(:dast_on_demand_scan_create) it_behaves_like 'an on-demand scan mutation when user can run an on-demand scan' do
end
context 'when a user does not have access to the project' do
it_behaves_like 'a mutation that returns top-level errors',
errors: ['The resource that you are attempting to access does not ' \
'exist or you don\'t have permission to perform this action']
end
context 'when a user does not have access to run a dast scan on the project' do
before do
project.add_guest(current_user)
end
it_behaves_like 'a mutation that returns top-level errors',
errors: ['The resource that you are attempting to access does not ' \
"exist or you don't have permission to perform this action"]
end
context 'when a user has access to run a dast scan on the project' do
before do
project.add_developer(current_user)
end
it 'returns a pipeline_url containing the correct path' do it 'returns a pipeline_url containing the correct path' do
post_graphql_mutation(mutation, current_user: current_user) post_graphql_mutation(mutation, current_user: current_user)
pipeline = Ci::Pipeline.last pipeline = Ci::Pipeline.last
...@@ -56,7 +31,7 @@ RSpec.describe 'Running a DAST Scan' do ...@@ -56,7 +31,7 @@ RSpec.describe 'Running a DAST Scan' do
context 'when wrong type of global id is passed' do context 'when wrong type of global id is passed' do
let(:mutation) do let(:mutation) do
graphql_mutation( graphql_mutation(
:dast_on_demand_scan_create, mutation_name,
full_path: full_path, full_path: full_path,
dast_site_profile_id: dast_site_profile.dast_site.to_global_id.to_s dast_site_profile_id: dast_site_profile.dast_site.to_global_id.to_s
) )
...@@ -81,15 +56,5 @@ RSpec.describe 'Running a DAST Scan' do ...@@ -81,15 +56,5 @@ RSpec.describe 'Running a DAST Scan' do
it_behaves_like 'a mutation that returns errors in the response', errors: ['error message'] it_behaves_like 'a mutation that returns errors in the response', errors: ['error message']
end end
context 'when on demand scan feature is disabled' do
before do
stub_feature_flags(security_on_demand_scans_feature_flag: false)
end
it_behaves_like 'a mutation that returns top-level errors',
errors: ['The resource that you are attempting to access does not ' \
"exist or you don't have permission to perform this action"]
end
end end
end end
...@@ -5,45 +5,20 @@ require 'spec_helper' ...@@ -5,45 +5,20 @@ require 'spec_helper'
RSpec.describe 'Creating a DAST Scanner Profile' do RSpec.describe 'Creating a DAST Scanner Profile' do
include GraphqlHelpers include GraphqlHelpers
let(:project) { create(:project, :repository, creator: current_user) }
let(:current_user) { create(:user) }
let(:full_path) { project.full_path }
let(:profile_name) { FFaker::Company.catch_phrase } let(:profile_name) { FFaker::Company.catch_phrase }
let(:dast_scanner_profile) { DastScannerProfile.find_by(project: project, name: profile_name) } let(:dast_scanner_profile) { DastScannerProfile.find_by(project: project, name: profile_name) }
let(:mutation_name) { :dast_scanner_profile_create }
let(:mutation) do let(:mutation) do
graphql_mutation( graphql_mutation(
:dast_scanner_profile_create, mutation_name,
full_path: full_path, full_path: full_path,
profile_name: profile_name profile_name: profile_name
) )
end end
def mutation_response it_behaves_like 'an on-demand scan mutation when user cannot run an on-demand scan'
graphql_mutation_response(:dast_scanner_profile_create) it_behaves_like 'an on-demand scan mutation when user can run an on-demand scan' do
end
context 'when a user does not have access to the project' do
it_behaves_like 'a mutation that returns top-level errors',
errors: ['The resource that you are attempting to access does not ' \
"exist or you don't have permission to perform this action"]
end
context 'when a user does not have access to run a dast scan on the project' do
before do
project.add_guest(current_user)
end
it_behaves_like 'a mutation that returns top-level errors',
errors: ['The resource that you are attempting to access does not ' \
"exist or you don't have permission to perform this action"]
end
context 'when a user has access to run a DAST scan on the project' do
before do
project.add_developer(current_user)
end
it 'returns the dast_scanner_profile id' do it 'returns the dast_scanner_profile id' do
post_graphql_mutation(mutation, current_user: current_user) post_graphql_mutation(mutation, current_user: current_user)
...@@ -61,15 +36,5 @@ RSpec.describe 'Creating a DAST Scanner Profile' do ...@@ -61,15 +36,5 @@ RSpec.describe 'Creating a DAST Scanner Profile' do
expect(mutation_response["errors"]).to include('Name has already been taken') expect(mutation_response["errors"]).to include('Name has already been taken')
end end
end end
context 'when on demand scan feature is disabled' do
before do
stub_feature_flags(security_on_demand_scans_feature_flag: false)
end
it_behaves_like 'a mutation that returns top-level errors',
errors: ['The resource that you are attempting to access does not ' \
"exist or you don't have permission to perform this action"]
end
end end
end end
...@@ -5,61 +5,34 @@ require 'spec_helper' ...@@ -5,61 +5,34 @@ require 'spec_helper'
RSpec.describe 'Creating a DAST Site Profile' do RSpec.describe 'Creating a DAST Site Profile' do
include GraphqlHelpers include GraphqlHelpers
let(:project) { create(:project, :repository, creator: current_user) }
let(:current_user) { create(:user) }
let(:full_path) { project.full_path }
let(:profile_name) { FFaker::Company.catch_phrase } let(:profile_name) { FFaker::Company.catch_phrase }
let(:target_url) { FFaker::Internet.uri(:https) } let(:target_url) { FFaker::Internet.uri(:https) }
let(:dast_site_profile) { DastSiteProfile.find_by(project: project, name: profile_name) } let(:dast_site_profile) { DastSiteProfile.find_by(project: project, name: profile_name) }
let(:mutation_name) { :dast_site_profile_create }
let(:mutation) do let(:mutation) do
graphql_mutation( graphql_mutation(
:dast_site_profile_create, mutation_name,
full_path: full_path, full_path: full_path,
profile_name: profile_name, profile_name: profile_name,
target_url: target_url target_url: target_url
) )
end end
def mutation_response it_behaves_like 'an on-demand scan mutation when user cannot run an on-demand scan'
graphql_mutation_response(:dast_site_profile_create) it_behaves_like 'an on-demand scan mutation when user can run an on-demand scan' do
end it 'returns the dast_site_profile id' do
subject
context 'when on demand scan feature is not enabled' do
it_behaves_like 'a mutation that returns top-level errors',
errors: ['The resource that you are attempting to access does not ' \
'exist or you don\'t have permission to perform this action']
end
context 'when on demand scan feature is enabled' do
before do
stub_feature_flags(security_on_demand_scans_feature_flag: true)
end
context 'when the user does not have permission to run a dast scan' do expect(mutation_response["id"]).to eq(dast_site_profile.to_global_id.to_s)
it_behaves_like 'a mutation that returns top-level errors',
errors: ['The resource that you are attempting to access does not ' \
'exist or you don\'t have permission to perform this action']
end end
context 'when the user can run a dast scan' do context 'when an unknown error occurs' do
before do before do
project.add_developer(current_user) allow(DastSiteProfile).to receive(:create!).and_raise(StandardError)
end end
it 'returns the dast_site_profile id' do it_behaves_like 'a mutation that returns top-level errors', errors: ['Internal server error']
post_graphql_mutation(mutation, current_user: current_user)
expect(mutation_response["id"]).to eq(dast_site_profile.to_global_id.to_s)
end
context 'when an unknown error occurs' do
before do
allow(DastSiteProfile).to receive(:create!).and_raise(StandardError)
end
it_behaves_like 'a mutation that returns top-level errors', errors: ['Internal server error']
end
end end
end end
end end
...@@ -5,52 +5,19 @@ require 'spec_helper' ...@@ -5,52 +5,19 @@ require 'spec_helper'
RSpec.describe 'Creating a DAST Site Profile' do RSpec.describe 'Creating a DAST Site Profile' do
include GraphqlHelpers include GraphqlHelpers
let(:project) { create(:project) }
let(:current_user) { create(:user) }
let(:full_path) { project.full_path }
let!(:dast_site_profile) { create(:dast_site_profile, project: project) } let!(:dast_site_profile) { create(:dast_site_profile, project: project) }
let(:mutation_name) { :dast_site_profile_delete }
let(:mutation) do let(:mutation) do
graphql_mutation( graphql_mutation(
:dast_site_profile_delete, mutation_name,
full_path: full_path, full_path: full_path,
id: dast_site_profile.to_global_id.to_s id: dast_site_profile.to_global_id.to_s
) )
end end
def mutation_response it_behaves_like 'an on-demand scan mutation when user cannot run an on-demand scan'
graphql_mutation_response(:dast_site_profile_delete) it_behaves_like 'an on-demand scan mutation when user can run an on-demand scan' do
end
subject { post_graphql_mutation(mutation, current_user: current_user) }
context 'when a user does not have access to the project' do
it_behaves_like 'a mutation that returns top-level errors',
errors: ['The resource that you are attempting to access does not ' \
'exist or you don\'t have permission to perform this action']
end
context 'when a user does not have access to run a dast scan on the project' do
before do
project.add_guest(current_user)
end
it_behaves_like 'a mutation that returns top-level errors',
errors: ['The resource that you are attempting to access does not ' \
'exist or you don\'t have permission to perform this action']
end
context 'when a user has access to run a dast scan on the project' do
before do
project.add_developer(current_user)
end
it 'returns an empty errors array' do
subject
expect(mutation_response["errors"]).to be_empty
end
it 'deletes the dast_site_profile' do it 'deletes the dast_site_profile' do
expect { subject }.to change { DastSiteProfile.count }.by(-1) expect { subject }.to change { DastSiteProfile.count }.by(-1)
end end
...@@ -77,41 +44,33 @@ RSpec.describe 'Creating a DAST Site Profile' do ...@@ -77,41 +44,33 @@ RSpec.describe 'Creating a DAST Site Profile' do
context 'when wrong type of global id is passed' do context 'when wrong type of global id is passed' do
let(:mutation) do let(:mutation) do
graphql_mutation( graphql_mutation(
:dast_site_profile_delete, mutation_name,
full_path: full_path, full_path: full_path,
id: dast_site_profile.dast_site.to_global_id.to_s id: dast_site_profile.dast_site.to_global_id.to_s
) )
end end
it 'returns a top-level error' do it_behaves_like 'a mutation that returns top-level errors' do
subject let(:match_errors) do
gid = dast_site_profile.dast_site.to_global_id
expect(graphql_errors.dig(0, 'message')).to include('does not represent an instance of DastSiteProfile') eq(["Variable $dastSiteProfileDeleteInput of type DastSiteProfileDeleteInput! " \
"was provided invalid value for id (\"#{gid}\" does not represent an instance " \
"of DastSiteProfile)"])
end
end end
end end
context 'when the dast_site_profile belongs to a different project' do context 'when the dast_site_profile belongs to a different project' do
let(:mutation) do let(:mutation) do
graphql_mutation( graphql_mutation(
:dast_site_profile_delete, mutation_name,
full_path: create(:project).full_path, full_path: create(:project).full_path,
id: dast_site_profile.to_global_id.to_s id: dast_site_profile.to_global_id.to_s
) )
end end
it_behaves_like 'a mutation that returns top-level errors', it_behaves_like 'a mutation that returns a top-level access error'
errors: ['The resource that you are attempting to access does not ' \
'exist or you don\'t have permission to perform this action']
end end
end end
context 'when on demand scan feature is disabled' do
before do
stub_feature_flags(security_on_demand_scans_feature_flag: false)
end
it_behaves_like 'a mutation that returns top-level errors',
errors: ['The resource that you are attempting to access does not ' \
'exist or you don\'t have permission to perform this action']
end
end end
...@@ -5,17 +5,15 @@ require 'spec_helper' ...@@ -5,17 +5,15 @@ require 'spec_helper'
RSpec.describe 'Creating a DAST Site Profile' do RSpec.describe 'Creating a DAST Site Profile' do
include GraphqlHelpers include GraphqlHelpers
let(:project) { create(:project) }
let(:current_user) { create(:user) }
let(:full_path) { project.full_path }
let!(:dast_site_profile) { create(:dast_site_profile, project: project) } let!(:dast_site_profile) { create(:dast_site_profile, project: project) }
let(:new_profile_name) { SecureRandom.hex } let(:new_profile_name) { SecureRandom.hex }
let(:new_target_url) { FFaker::Internet.uri(:https) } let(:new_target_url) { FFaker::Internet.uri(:https) }
let(:mutation_name) { :dast_site_profile_update }
let(:mutation) do let(:mutation) do
graphql_mutation( graphql_mutation(
:dast_site_profile_update, mutation_name,
full_path: full_path, full_path: full_path,
id: dast_site_profile.to_global_id.to_s, id: dast_site_profile.to_global_id.to_s,
profile_name: new_profile_name, profile_name: new_profile_name,
...@@ -24,38 +22,11 @@ RSpec.describe 'Creating a DAST Site Profile' do ...@@ -24,38 +22,11 @@ RSpec.describe 'Creating a DAST Site Profile' do
end end
def mutation_response def mutation_response
graphql_mutation_response(:dast_site_profile_update) graphql_mutation_response(mutation_name)
end end
subject { post_graphql_mutation(mutation, current_user: current_user) } it_behaves_like 'an on-demand scan mutation when user cannot run an on-demand scan'
it_behaves_like 'an on-demand scan mutation when user can run an on-demand scan' do
context 'when a user does not have access to the project' do
it_behaves_like 'a mutation that returns top-level errors',
errors: ['The resource that you are attempting to access does not ' \
'exist or you don\'t have permission to perform this action']
end
context 'when a user does not have access to run a dast scan on the project' do
before do
project.add_guest(current_user)
end
it_behaves_like 'a mutation that returns top-level errors',
errors: ['The resource that you are attempting to access does not ' \
'exist or you don\'t have permission to perform this action']
end
context 'when a user has access to run a dast scan on the project' do
before do
project.add_developer(current_user)
end
it 'returns an empty errors array' do
subject
expect(mutation_response["errors"]).to be_empty
end
it 'updates the dast_site_profile' do it 'updates the dast_site_profile' do
subject subject
...@@ -84,7 +55,7 @@ RSpec.describe 'Creating a DAST Site Profile' do ...@@ -84,7 +55,7 @@ RSpec.describe 'Creating a DAST Site Profile' do
context 'when wrong type of global id is passed' do context 'when wrong type of global id is passed' do
let(:mutation) do let(:mutation) do
graphql_mutation( graphql_mutation(
:dast_site_profile_update, mutation_name,
full_path: full_path, full_path: full_path,
id: dast_site_profile.dast_site.to_global_id.to_s, id: dast_site_profile.dast_site.to_global_id.to_s,
profile_name: new_profile_name, profile_name: new_profile_name,
...@@ -92,17 +63,21 @@ RSpec.describe 'Creating a DAST Site Profile' do ...@@ -92,17 +63,21 @@ RSpec.describe 'Creating a DAST Site Profile' do
) )
end end
it 'returns a top-level error' do it_behaves_like 'a mutation that returns top-level errors' do
subject let(:match_errors) do
gid = dast_site_profile.dast_site.to_global_id
expect(graphql_errors.dig(0, 'message')).to include('does not represent an instance of DastSiteProfile') eq(["Variable $dastSiteProfileUpdateInput of type DastSiteProfileUpdateInput! " \
"was provided invalid value for id (\"#{gid}\" does not represent an instance " \
"of DastSiteProfile)"])
end
end end
end end
context 'when the dast_site_profile belongs to a different project' do context 'when the dast_site_profile belongs to a different project' do
let(:mutation) do let(:mutation) do
graphql_mutation( graphql_mutation(
:dast_site_profile_update, mutation_name,
full_path: create(:project).full_path, full_path: create(:project).full_path,
id: dast_site_profile.to_global_id.to_s, id: dast_site_profile.to_global_id.to_s,
profile_name: new_profile_name, profile_name: new_profile_name,
...@@ -110,19 +85,7 @@ RSpec.describe 'Creating a DAST Site Profile' do ...@@ -110,19 +85,7 @@ RSpec.describe 'Creating a DAST Site Profile' do
) )
end end
it_behaves_like 'a mutation that returns top-level errors', it_behaves_like 'a mutation that returns a top-level access error'
errors: ['The resource that you are attempting to access does not ' \
'exist or you don\'t have permission to perform this action']
end end
end end
context 'when on demand scan feature is disabled' do
before do
stub_feature_flags(security_on_demand_scans_feature_flag: false)
end
it_behaves_like 'a mutation that returns top-level errors',
errors: ['The resource that you are attempting to access does not ' \
'exist or you don\'t have permission to perform this action']
end
end end
...@@ -26,6 +26,10 @@ RSpec.describe 'Running a DAST Scan' do ...@@ -26,6 +26,10 @@ RSpec.describe 'Running a DAST Scan' do
graphql_mutation_response(:run_dast_scan) graphql_mutation_response(:run_dast_scan)
end end
before do
stub_licensed_features(security_on_demand_scans: true)
end
context 'when on demand scan feature is not enabled' do context 'when on demand scan feature is not enabled' do
it_behaves_like 'a mutation that returns top-level errors', it_behaves_like 'a mutation that returns top-level errors',
errors: ['The resource that you are attempting to access does not ' \ errors: ['The resource that you are attempting to access does not ' \
......
...@@ -40,7 +40,7 @@ RSpec.describe 'Query.project(fullPath).dastScannerProfiles' do ...@@ -40,7 +40,7 @@ RSpec.describe 'Query.project(fullPath).dastScannerProfiles' do
end end
end end
context 'when a user does not have access to run_ondemand_dast_scan' do context 'when the user can run a dast scan' do
before do before do
project.add_guest(current_user) project.add_guest(current_user)
end end
......
...@@ -8,6 +8,10 @@ RSpec.describe Ci::RunDastScanService do ...@@ -8,6 +8,10 @@ RSpec.describe Ci::RunDastScanService do
let(:branch) { project.default_branch } let(:branch) { project.default_branch }
let(:target_url) { FFaker::Internet.uri(:http) } let(:target_url) { FFaker::Internet.uri(:http) }
before do
stub_licensed_features(security_on_demand_scans: true)
end
describe '.ci_template' do describe '.ci_template' do
it 'builds a hash' do it 'builds a hash' do
expect(described_class.ci_template).to be_a(Hash) expect(described_class.ci_template).to be_a(Hash)
...@@ -29,7 +33,7 @@ RSpec.describe Ci::RunDastScanService do ...@@ -29,7 +33,7 @@ RSpec.describe Ci::RunDastScanService do
let(:pipeline) { subject.payload } let(:pipeline) { subject.payload }
let(:message) { subject.message } let(:message) { subject.message }
context 'when the user does not have permission to run a dast scan' do context 'when a user does not have access to the project' do
it 'returns an error status' do it 'returns an error status' do
expect(status).to eq(:error) expect(status).to eq(:error)
end end
...@@ -142,6 +146,34 @@ RSpec.describe Ci::RunDastScanService do ...@@ -142,6 +146,34 @@ RSpec.describe Ci::RunDastScanService do
expect(message).to eq(full_error_messages) expect(message).to eq(full_error_messages)
end end
end end
context 'when on demand scan feature is disabled' do
before do
stub_feature_flags(security_on_demand_scans_feature_flag: false)
end
it 'returns an error status' do
expect(status).to eq(:error)
end
it 'populates message' do
expect(message).to eq('Insufficient permissions')
end
end
context 'when on demand scan licensed feature is not available' do
before do
stub_licensed_features(security_on_demand_scans: false)
end
it 'returns an error status' do
expect(status).to eq(:error)
end
it 'populates message' do
expect(message).to eq('Insufficient permissions')
end
end
end end
end end
end end
...@@ -9,6 +9,10 @@ RSpec.describe DastScannerProfiles::CreateService do ...@@ -9,6 +9,10 @@ RSpec.describe DastScannerProfiles::CreateService do
let(:target_timeout) { 60 } let(:target_timeout) { 60 }
let(:spider_timeout) { 600 } let(:spider_timeout) { 600 }
before do
stub_licensed_features(security_on_demand_scans: true)
end
describe '#execute' do describe '#execute' do
subject do subject do
described_class.new(project, user).execute( described_class.new(project, user).execute(
...@@ -83,6 +87,34 @@ RSpec.describe DastScannerProfiles::CreateService do ...@@ -83,6 +87,34 @@ RSpec.describe DastScannerProfiles::CreateService do
expect(message).to eq(['Name has already been taken']) expect(message).to eq(['Name has already been taken'])
end end
end end
context 'when on demand scan feature is disabled' do
before do
stub_feature_flags(security_on_demand_scans_feature_flag: false)
end
it 'returns an error status' do
expect(status).to eq(:error)
end
it 'populates message' do
expect(message).to eq('Insufficient permissions')
end
end
context 'when on demand scan licensed feature is not available' do
before do
stub_licensed_features(security_on_demand_scans: false)
end
it 'returns an error status' do
expect(status).to eq(:error)
end
it 'populates message' do
expect(message).to eq('Insufficient permissions')
end
end
end end
end end
end end
...@@ -8,6 +8,10 @@ RSpec.describe DastSiteProfiles::CreateService do ...@@ -8,6 +8,10 @@ RSpec.describe DastSiteProfiles::CreateService do
let(:name) { FFaker::Company.catch_phrase } let(:name) { FFaker::Company.catch_phrase }
let(:target_url) { FFaker::Internet.uri(:http) } let(:target_url) { FFaker::Internet.uri(:http) }
before do
stub_licensed_features(security_on_demand_scans: true)
end
describe '#execute' do describe '#execute' do
subject { described_class.new(project, user).execute(name: name, target_url: target_url) } subject { described_class.new(project, user).execute(name: name, target_url: target_url) }
...@@ -16,7 +20,7 @@ RSpec.describe DastSiteProfiles::CreateService do ...@@ -16,7 +20,7 @@ RSpec.describe DastSiteProfiles::CreateService do
let(:errors) { subject.errors } let(:errors) { subject.errors }
let(:payload) { subject.payload } let(:payload) { subject.payload }
context 'when the user does not have permission to run a dast scan' do context 'when a user does not have access to the project' do
it 'returns an error status' do it 'returns an error status' do
expect(status).to eq(:error) expect(status).to eq(:error)
end end
...@@ -72,6 +76,34 @@ RSpec.describe DastSiteProfiles::CreateService do ...@@ -72,6 +76,34 @@ RSpec.describe DastSiteProfiles::CreateService do
expect(errors).to include('Url is blocked: Requests to localhost are not allowed') expect(errors).to include('Url is blocked: Requests to localhost are not allowed')
end end
end end
context 'when on demand scan feature is disabled' do
before do
stub_feature_flags(security_on_demand_scans_feature_flag: false)
end
it 'returns an error status' do
expect(status).to eq(:error)
end
it 'populates message' do
expect(message).to eq('Insufficient permissions')
end
end
context 'when on demand scan licensed feature is not available' do
before do
stub_licensed_features(security_on_demand_scans: false)
end
it 'returns an error status' do
expect(status).to eq(:error)
end
it 'populates message' do
expect(message).to eq('Insufficient permissions')
end
end
end end
end end
end end
...@@ -10,6 +10,10 @@ RSpec.describe DastSiteProfiles::UpdateService do ...@@ -10,6 +10,10 @@ RSpec.describe DastSiteProfiles::UpdateService do
let(:new_profile_name) { SecureRandom.hex } let(:new_profile_name) { SecureRandom.hex }
let(:new_target_url) { FFaker::Internet.uri(:https) } let(:new_target_url) { FFaker::Internet.uri(:https) }
before do
stub_licensed_features(security_on_demand_scans: true)
end
describe '#execute' do describe '#execute' do
subject do subject do
described_class.new(project, user).execute( described_class.new(project, user).execute(
...@@ -24,7 +28,7 @@ RSpec.describe DastSiteProfiles::UpdateService do ...@@ -24,7 +28,7 @@ RSpec.describe DastSiteProfiles::UpdateService do
let(:errors) { subject.errors } let(:errors) { subject.errors }
let(:payload) { subject.payload } let(:payload) { subject.payload }
context 'when the user does not have permission to run a dast scan' do context 'when a user does not have access to the project' do
it 'returns an error status' do it 'returns an error status' do
expect(status).to eq(:error) expect(status).to eq(:error)
end end
...@@ -81,6 +85,34 @@ RSpec.describe DastSiteProfiles::UpdateService do ...@@ -81,6 +85,34 @@ RSpec.describe DastSiteProfiles::UpdateService do
expect(message).to eq('DastSiteProfile not found') expect(message).to eq('DastSiteProfile not found')
end end
end end
context 'when on demand scan feature is disabled' do
before do
stub_feature_flags(security_on_demand_scans_feature_flag: false)
end
it 'returns an error status' do
expect(status).to eq(:error)
end
it 'populates message' do
expect(message).to eq('Insufficient permissions')
end
end
context 'when on demand scan licensed feature is not available' do
before do
stub_licensed_features(security_on_demand_scans: false)
end
it 'returns an error status' do
expect(status).to eq(:error)
end
it 'populates message' do
expect(message).to eq('Insufficient permissions')
end
end
end end
end end
end end
...@@ -7,10 +7,14 @@ RSpec.describe DastSites::FindOrCreateService do ...@@ -7,10 +7,14 @@ RSpec.describe DastSites::FindOrCreateService do
let(:project) { create(:project, :repository, creator: user) } let(:project) { create(:project, :repository, creator: user) }
let(:url) { FFaker::Internet.uri(:http) } let(:url) { FFaker::Internet.uri(:http) }
before do
stub_licensed_features(security_on_demand_scans: true)
end
describe '#execute!' do describe '#execute!' do
subject { described_class.new(project, user).execute!(url: url) } subject { described_class.new(project, user).execute!(url: url) }
context 'when the user does not have permission to run a dast scan' do context 'when a user does not have access to the project' do
it 'raises an exception' do it 'raises an exception' do
expect { subject }.to raise_error(DastSites::FindOrCreateService::PermissionsError) do |err| expect { subject }.to raise_error(DastSites::FindOrCreateService::PermissionsError) do |err|
expect(err.message).to include('Insufficient permissions') expect(err.message).to include('Insufficient permissions')
...@@ -54,6 +58,26 @@ RSpec.describe DastSites::FindOrCreateService do ...@@ -54,6 +58,26 @@ RSpec.describe DastSites::FindOrCreateService do
end end
end end
end end
context 'when on demand scan feature is disabled' do
it 'raises an exception' do
stub_feature_flags(security_on_demand_scans_feature_flag: false)
expect { subject }.to raise_error(DastSites::FindOrCreateService::PermissionsError) do |err|
expect(err.message).to include('Insufficient permissions')
end
end
end
context 'when on demand scan licensed feature is not available' do
it 'raises an exception' do
stub_licensed_features(security_on_demand_scans: false)
expect { subject }.to raise_error(DastSites::FindOrCreateService::PermissionsError) do |err|
expect(err.message).to include('Insufficient permissions')
end
end
end
end end
end end
end end
# frozen_string_literal: true
require 'spec_helper'
# There must be a method or let called `mutation` defined that executes
# the mutation and one called `mutation_name` that is the name of the
# mutation being executed.
RSpec.shared_examples 'an on-demand scan mutation when user can run an on-demand scan' do
let(:project) { create(:project, :repository, creator: current_user) }
let(:current_user) { create(:user) }
let(:full_path) { project.full_path }
def mutation_response
graphql_mutation_response(mutation_name)
end
subject { post_graphql_mutation(mutation, current_user: current_user) }
before do
stub_licensed_features(security_on_demand_scans: true)
project.add_developer(current_user)
end
it 'returns an empty errors array' do
subject
expect(mutation_response["errors"]).to be_empty
end
context 'when on demand scan feature is disabled' do
before do
stub_feature_flags(security_on_demand_scans_feature_flag: false)
end
it_behaves_like 'a mutation that returns a top-level access error'
end
context 'when on demand scan licensed feature is not available' do
before do
stub_licensed_features(security_on_demand_scans: false)
end
it_behaves_like 'a mutation that returns a top-level access error'
end
end
# frozen_string_literal: true
require 'spec_helper'
# There must be a method or let called `mutation` defined that executes
# the mutation and one called `mutation_name` that is the name of the
# mutation being executed.
RSpec.shared_examples 'an on-demand scan mutation when user cannot run an on-demand scan' do
let(:project) { create(:project, :repository, creator: current_user) }
let(:current_user) { create(:user) }
let(:full_path) { project.full_path }
before do
stub_licensed_features(security_on_demand_scans: true)
end
context 'when a user does not have access to the project' do
it_behaves_like 'a mutation that returns a top-level access error'
end
context 'when a user does not have access to run a dast scan on the project' do
before do
project.add_guest(current_user)
end
it_behaves_like 'a mutation that returns a top-level access error'
end
end
...@@ -19,6 +19,13 @@ RSpec.shared_examples 'a mutation that returns top-level errors' do |errors: []| ...@@ -19,6 +19,13 @@ RSpec.shared_examples 'a mutation that returns top-level errors' do |errors: []|
end end
end end
# There must be a method or let called `mutation` defined that executes
# the mutation.
RSpec.shared_examples 'a mutation that returns a top-level access error' do
include_examples 'a mutation that returns top-level errors',
errors: [Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR]
end
RSpec.shared_examples 'an invalid argument to the mutation' do |argument_name:| RSpec.shared_examples 'an invalid argument to the mutation' do |argument_name:|
it_behaves_like 'a mutation that returns top-level errors' do it_behaves_like 'a mutation that returns top-level errors' do
let(:match_errors) do let(:match_errors) 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