From 90fa7b72e6dc0ee17ef00641a5f2fcd684a153c0 Mon Sep 17 00:00:00 2001 From: Miki Amos Date: Thu, 21 Aug 2025 17:36:19 +0300 Subject: [PATCH 1/6] Add ci runner tags to dast site validation Changelog: fixed EE: true --- .../dast/site_validations/runner_service.rb | 46 +++++++++- .../site_validations/runner_service_spec.rb | 86 +++++++++++++++++++ 2 files changed, 131 insertions(+), 1 deletion(-) diff --git a/ee/app/services/app_sec/dast/site_validations/runner_service.rb b/ee/app/services/app_sec/dast/site_validations/runner_service.rb index 63357939b780ab..992a791ad40644 100644 --- a/ee/app/services/app_sec/dast/site_validations/runner_service.rb +++ b/ee/app/services/app_sec/dast/site_validations/runner_service.rb @@ -7,6 +7,10 @@ class RunnerService < BaseProjectService def execute return ServiceResponse.error(message: _('Insufficient permissions')) unless allowed? + unless available_runners_exists? + return ServiceResponse.error(message: _('No suitable runners available for DAST validation')) + end + service = Ci::CreatePipelineService.new(project, current_user, ref: project.default_branch_or_main) result = service.execute(:ondemand_dast_validation, content: ci_configuration.to_yaml, variables_attributes: dast_site_validation_variables) @@ -30,7 +34,47 @@ def dast_site_validation end def ci_configuration - { 'include' => [{ 'template' => 'Security/DAST-Runner-Validation.gitlab-ci.yml' }] } + ci_config = { + 'include' => [{ 'template' => 'Security/DAST-Runner-Validation.gitlab-ci.yml' }] + } + + ci_config['validation'] = { 'tags' => [dast_validation_tag] } if tagged_runners_available? + + ci_config + end + + def dast_validation_tag + 'Dast Validation Tag' + end + + def tagged_runners_available? + dast_site_validation_runner.exists? + end + + def available_runners_exists? + tagged_runners_available? || untagged_runners_available? + end + + def dast_site_validation_runner + ::Ci::RunnersFinder.new( + current_user: current_user, + params: { + project_id: project.id, + tag_name: dast_validation_tag, + status: 'active' + } + ).execute + end + + def untagged_runners_available? + ::Ci::RunnersFinder.new( + current_user: current_user, + params: { + project_id: project.id, + status: 'active', + run_untagged: true + } + ).execute.exists? end def dast_site_validation_variables diff --git a/ee/spec/services/app_sec/dast/site_validations/runner_service_spec.rb b/ee/spec/services/app_sec/dast/site_validations/runner_service_spec.rb index cd4779032a9555..6649a340945041 100644 --- a/ee/spec/services/app_sec/dast/site_validations/runner_service_spec.rb +++ b/ee/spec/services/app_sec/dast/site_validations/runner_service_spec.rb @@ -94,6 +94,92 @@ end end + context 'when no suitable runners are available' do + before do + allow_next_instance_of(described_class) do |instance| + allow(instance).to receive(:available_runners_for_site_validation?).and_return(false) + end + end + + it 'returns an error' do + expect(subject).to have_attributes( + status: :error, + message: 'No suitable runners available for DAST validation' + ) + end + end + + context 'when tagged runners are available' do + let_it_be(:ci_tag) { create(:ci_tag, name: 'Dast Validation Tag') } + let_it_be(:tagged_runner) { create(:ci_runner, :project, projects: [project], tag_list: [ci_tag.name]) } + + before do + # Create the runner-tag association + create(:ci_runner_tagging, runner: tagged_runner, tag: ci_tag) + end + + it 'creates pipeline with tagged configuration' do + expect { subject }.to change { Ci::Pipeline.count }.by(1) + + pipeline = Ci::Pipeline.last + expect(pipeline.source).to eq('ondemand_dast_validation') + end + + it 'sets tags in ci_configuration' do + service = described_class.new(project: project, current_user: developer, params: { dast_site_validation: dast_site_validation }) + config = service.send(:ci_configuration) + + expect(config['validation']['tags']).to eq(['Dast Validation Tag']) + end + end + + context 'when only untagged runners are available' do + let_it_be(:untagged_runner) { create(:ci_runner, :project, projects: [project], run_untagged: true) } + + before do + allow_next_instance_of(described_class) do |instance| + allow(instance).to receive(:tagged_runners_available?).and_return(false) + allow(instance).to receive(:untagged_runners_available?).and_return(true) + end + end + + it 'creates pipeline without tags configuration' do + expect { subject }.to change { Ci::Pipeline.count }.by(1) + + pipeline = Ci::Pipeline.last + expect(pipeline.source).to eq('ondemand_dast_validation') + end + + it 'does not set validation entry in ci_configuration' do + service = described_class.new(project: project, current_user: developer, params: { dast_site_validation: dast_site_validation }) + + allow(service).to receive(:tagged_runners_available?).and_return(false) + allow(service).to receive(:untagged_runners_available?).and_return(true) + + config = service.send(:ci_configuration) + + expect(config).not_to have_key('validation') + end + end + + context 'when both tagged and untagged runners are available' do + let_it_be(:ci_tag) { create(:ci_tag, name: 'Dast Validation Tag') } + let_it_be(:tagged_runner) { create(:ci_runner, :project, projects: [project], tag_list: [ci_tag.name]) } + let_it_be(:untagged_runner) { create(:ci_runner, :project, projects: [project], run_untagged: true) } + + before do + # Create the runner-tag association + create(:ci_runner_tagging, runner: tagged_runner, tag: ci_tag) + end + + it 'prioritizes tagged runners and sets tags in configuration' do + service = described_class.new(project: project, current_user: developer, params: { dast_site_validation: dast_site_validation }) + config = service.send(:ci_configuration) + + expect(config['validation']['tags']).to eq(['Dast Validation Tag']) + end + end + context 'when pipeline creation fails' do before do allow_next_instance_of(Ci::Pipeline) do |instance| -- GitLab From e3b8e7953e2e64d5647b70574b0f3680915c9052 Mon Sep 17 00:00:00 2001 From: Miki Amos Date: Thu, 21 Aug 2025 17:40:26 +0300 Subject: [PATCH 2/6] Modify gitlab.pot --- locale/gitlab.pot | 3 +++ 1 file changed, 3 insertions(+) diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 131e7ea8b4423d..02d26aef9a3399 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -42573,6 +42573,9 @@ msgstr "" msgid "No suggestions found" msgstr "" +msgid "No suitable runners available for DAST validation" +msgstr "" + msgid "No template" msgstr "" -- GitLab From 235af72eb0639c4b9ffeb9d0b22e8e7eb260b5b0 Mon Sep 17 00:00:00 2001 From: Miki Amos Date: Mon, 25 Aug 2025 11:20:16 +0300 Subject: [PATCH 3/6] Fix unit tests --- .../find_or_create_service_spec.rb | 11 ++++ .../site_validations/runner_service_spec.rb | 57 ++++++++++++++----- 2 files changed, 55 insertions(+), 13 deletions(-) diff --git a/ee/spec/services/app_sec/dast/site_validations/find_or_create_service_spec.rb b/ee/spec/services/app_sec/dast/site_validations/find_or_create_service_spec.rb index 26642f0c2232d2..d8617fb10e79ec 100644 --- a/ee/spec/services/app_sec/dast/site_validations/find_or_create_service_spec.rb +++ b/ee/spec/services/app_sec/dast/site_validations/find_or_create_service_spec.rb @@ -14,6 +14,9 @@ before do project.update!(ci_pipeline_variables_minimum_override_role: :developer) + # Grant admin permissions to avoid access denied errors in Ci::RunnersFinder + allow(Ability).to receive(:allowed?).and_call_original + allow(Ability).to receive(:allowed?).with(developer, :read_admin_cicd).and_return(true) end describe 'execute', :clean_gitlab_redis_shared_state do @@ -31,6 +34,14 @@ context 'when the licensed feature is available' do before do stub_licensed_features(security_on_demand_scans: true) + # Mock runner availability for successful execution + allow_next_instance_of(AppSec::Dast::SiteValidations::RunnerService) do |instance| + allow(instance).to receive_messages( + available_runners_exists?: true, + tagged_runners_available?: false, + untagged_runners_available?: true + ) + end end it 'communicates success' do diff --git a/ee/spec/services/app_sec/dast/site_validations/runner_service_spec.rb b/ee/spec/services/app_sec/dast/site_validations/runner_service_spec.rb index 6649a340945041..a73c9c18b14356 100644 --- a/ee/spec/services/app_sec/dast/site_validations/runner_service_spec.rb +++ b/ee/spec/services/app_sec/dast/site_validations/runner_service_spec.rb @@ -14,6 +14,9 @@ before do project.update!(ci_pipeline_variables_minimum_override_role: :developer) + # Grant admin permissions to avoid access denied errors in Ci::RunnersFinder + allow(Ability).to receive(:allowed?).and_call_original + allow(Ability).to receive(:allowed?).with(developer, :read_admin_cicd).and_return(true) end describe 'execute' do @@ -37,6 +40,12 @@ context 'when the feature is enabled' do before do stub_licensed_features(security_on_demand_scans: true) + # Mock runner availability for basic tests + allow_next_instance_of(described_class) do |instance| + allow(instance).to receive(:available_runners_exists?).and_return(true) + allow(instance).to receive(:tagged_runners_available?).and_return(false) + allow(instance).to receive(:untagged_runners_available?).and_return(true) + end end it 'is allowed to set pipeline variables regardless of minimum override role' do @@ -97,7 +106,7 @@ context 'when no suitable runners are available' do before do allow_next_instance_of(described_class) do |instance| - allow(instance).to receive(:available_runners_for_site_validation?).and_return(false) + allow(instance).to receive(:available_runners_exists?).and_return(false) end end @@ -110,12 +119,20 @@ end context 'when tagged runners are available' do - let_it_be(:ci_tag) { create(:ci_tag, name: 'Dast Validation Tag') } - let_it_be(:tagged_runner) { create(:ci_runner, :project, projects: [project], tag_list: [ci_tag.name]) } + let(:ci_tag) { create(:ci_tag, name: 'Dast Validation Tag') } + let(:tagged_runner) { create(:ci_runner, :project, projects: [project]) } before do - # Create the runner-tag association - create(:ci_runner_tagging, runner: tagged_runner, tag: ci_tag) + # Create the runner-tag association (avoid duplicates) + unless tagged_runner.taggings.joins(:tag).where(tags: { name: ci_tag.name }).exists? + create(:ci_runner_tagging, runner: tagged_runner, tag: ci_tag) + end + # Override the mocks for this context + allow_next_instance_of(described_class) do |instance| + allow(instance).to receive(:available_runners_exists?).and_return(true) + allow(instance).to receive(:tagged_runners_available?).and_return(true) + allow(instance).to receive(:untagged_runners_available?).and_return(false) + end end it 'creates pipeline with tagged configuration' do @@ -138,6 +155,7 @@ before do allow_next_instance_of(described_class) do |instance| + allow(instance).to receive(:available_runners_exists?).and_return(true) allow(instance).to receive(:tagged_runners_available?).and_return(false) allow(instance).to receive(:untagged_runners_available?).and_return(true) end @@ -163,13 +181,21 @@ end context 'when both tagged and untagged runners are available' do - let_it_be(:ci_tag) { create(:ci_tag, name: 'Dast Validation Tag') } - let_it_be(:tagged_runner) { create(:ci_runner, :project, projects: [project], tag_list: [ci_tag.name]) } - let_it_be(:untagged_runner) { create(:ci_runner, :project, projects: [project], run_untagged: true) } + let(:ci_tag_2) { create(:ci_tag, name: 'Dast Validation Tag') } + let(:tagged_runner_2) { create(:ci_runner, :project, projects: [project]) } + let(:untagged_runner) { create(:ci_runner, :project, projects: [project], run_untagged: true) } before do - # Create the runner-tag association - create(:ci_runner_tagging, runner: tagged_runner, tag: ci_tag) + # Create the runner-tag association (avoid duplicates) + unless tagged_runner_2.taggings.joins(:tag).where(tags: { name: ci_tag_2.name }).exists? + create(:ci_runner_tagging, runner: tagged_runner_2, tag: ci_tag_2) + end + # Override the mocks for this context + allow_next_instance_of(described_class) do |instance| + allow(instance).to receive(:available_runners_exists?).and_return(true) + allow(instance).to receive(:tagged_runners_available?).and_return(true) + allow(instance).to receive(:untagged_runners_available?).and_return(true) + end end it 'prioritizes tagged runners and sets tags in configuration' do @@ -182,9 +208,14 @@ context 'when pipeline creation fails' do before do - allow_next_instance_of(Ci::Pipeline) do |instance| - allow(instance).to receive(:created_successfully?).and_return(false) - allow(instance).to receive(:full_error_messages).and_return('error message') + # Mock successful Ci::CreatePipelineService result but failed pipeline + allow_next_instance_of(Ci::CreatePipelineService) do |instance| + mock_result = instance_double(ServiceResponse, success?: false) + allow(instance).to receive(:execute).and_return(mock_result) + end + # Mock runner availability to pass the initial check + allow_next_instance_of(described_class) do |instance| + allow(instance).to receive(:available_runners_exists?).and_return(true) end end -- GitLab From 3e4e5673498110a10ff1593c372facecb4cbfdf7 Mon Sep 17 00:00:00 2001 From: Miki Amos Date: Mon, 1 Sep 2025 13:39:47 +0300 Subject: [PATCH 4/6] Fix code review comments --- .../dast/site_validations/runner_service.rb | 46 ++++++++--------- .../find_or_create_service_spec.rb | 1 + .../site_validations/runner_service_spec.rb | 51 +++---------------- 3 files changed, 31 insertions(+), 67 deletions(-) diff --git a/ee/app/services/app_sec/dast/site_validations/runner_service.rb b/ee/app/services/app_sec/dast/site_validations/runner_service.rb index 992a791ad40644..60e1ef575e801b 100644 --- a/ee/app/services/app_sec/dast/site_validations/runner_service.rb +++ b/ee/app/services/app_sec/dast/site_validations/runner_service.rb @@ -7,7 +7,7 @@ class RunnerService < BaseProjectService def execute return ServiceResponse.error(message: _('Insufficient permissions')) unless allowed? - unless available_runners_exists? + unless available_runners_exist? return ServiceResponse.error(message: _('No suitable runners available for DAST validation')) end @@ -44,39 +44,39 @@ def ci_configuration end def dast_validation_tag - 'Dast Validation Tag' + 'dast-validation-runner' end - def tagged_runners_available? - dast_site_validation_runner.exists? - end - - def available_runners_exists? + def available_runners_exist? tagged_runners_available? || untagged_runners_available? end - def dast_site_validation_runner - ::Ci::RunnersFinder.new( - current_user: current_user, - params: { - project_id: project.id, - tag_name: dast_validation_tag, - status: 'active' - } - ).execute - end + def runners_available?(tagged: false) + params = { + project: project, + status: 'active' + } + + if tagged + params[:tag_name] = dast_validation_tag + else + params[:run_untagged] = true + end - def untagged_runners_available? ::Ci::RunnersFinder.new( current_user: current_user, - params: { - project_id: project.id, - status: 'active', - run_untagged: true - } + params: params ).execute.exists? end + strong_memoize_attr def tagged_runners_available? + runners_available?(tagged: true) + end + + strong_memoize_attr def untagged_runners_available? + runners_available?(tagged: false) + end + def dast_site_validation_variables [ { key: 'DAST_SITE_VALIDATION_ID', secret_value: String(dast_site_validation.id) }, diff --git a/ee/spec/services/app_sec/dast/site_validations/find_or_create_service_spec.rb b/ee/spec/services/app_sec/dast/site_validations/find_or_create_service_spec.rb index d8617fb10e79ec..c264acbc268dfb 100644 --- a/ee/spec/services/app_sec/dast/site_validations/find_or_create_service_spec.rb +++ b/ee/spec/services/app_sec/dast/site_validations/find_or_create_service_spec.rb @@ -17,6 +17,7 @@ # Grant admin permissions to avoid access denied errors in Ci::RunnersFinder allow(Ability).to receive(:allowed?).and_call_original allow(Ability).to receive(:allowed?).with(developer, :read_admin_cicd).and_return(true) + allow(Ability).to receive(:allowed?).with(developer, :read_runners, project).and_return(true) end describe 'execute', :clean_gitlab_redis_shared_state do diff --git a/ee/spec/services/app_sec/dast/site_validations/runner_service_spec.rb b/ee/spec/services/app_sec/dast/site_validations/runner_service_spec.rb index a73c9c18b14356..ba632ce505a62f 100644 --- a/ee/spec/services/app_sec/dast/site_validations/runner_service_spec.rb +++ b/ee/spec/services/app_sec/dast/site_validations/runner_service_spec.rb @@ -7,6 +7,7 @@ let_it_be(:developer) { create(:user, developer_of: project) } let_it_be(:dast_site_token) { create(:dast_site_token, project: project) } let_it_be(:dast_site_validation) { create(:dast_site_validation, dast_site_token: dast_site_token) } + let_it_be(:default_runner) { create(:ci_runner, :project, projects: [project], run_untagged: true) } subject do described_class.new(project: project, current_user: developer, params: { dast_site_validation: dast_site_validation }).execute @@ -17,6 +18,7 @@ # Grant admin permissions to avoid access denied errors in Ci::RunnersFinder allow(Ability).to receive(:allowed?).and_call_original allow(Ability).to receive(:allowed?).with(developer, :read_admin_cicd).and_return(true) + allow(Ability).to receive(:allowed?).with(developer, :read_runners, project).and_return(true) end describe 'execute' do @@ -40,12 +42,6 @@ context 'when the feature is enabled' do before do stub_licensed_features(security_on_demand_scans: true) - # Mock runner availability for basic tests - allow_next_instance_of(described_class) do |instance| - allow(instance).to receive(:available_runners_exists?).and_return(true) - allow(instance).to receive(:tagged_runners_available?).and_return(false) - allow(instance).to receive(:untagged_runners_available?).and_return(true) - end end it 'is allowed to set pipeline variables regardless of minimum override role' do @@ -106,7 +102,7 @@ context 'when no suitable runners are available' do before do allow_next_instance_of(described_class) do |instance| - allow(instance).to receive(:available_runners_exists?).and_return(false) + allow(instance).to receive(:available_runners_exist?).and_return(false) end end @@ -119,7 +115,7 @@ end context 'when tagged runners are available' do - let(:ci_tag) { create(:ci_tag, name: 'Dast Validation Tag') } + let(:ci_tag) { create(:ci_tag, name: 'dast-validation-runner') } let(:tagged_runner) { create(:ci_runner, :project, projects: [project]) } before do @@ -127,12 +123,6 @@ unless tagged_runner.taggings.joins(:tag).where(tags: { name: ci_tag.name }).exists? create(:ci_runner_tagging, runner: tagged_runner, tag: ci_tag) end - # Override the mocks for this context - allow_next_instance_of(described_class) do |instance| - allow(instance).to receive(:available_runners_exists?).and_return(true) - allow(instance).to receive(:tagged_runners_available?).and_return(true) - allow(instance).to receive(:untagged_runners_available?).and_return(false) - end end it 'creates pipeline with tagged configuration' do @@ -145,22 +135,11 @@ it 'sets tags in ci_configuration' do service = described_class.new(project: project, current_user: developer, params: { dast_site_validation: dast_site_validation }) config = service.send(:ci_configuration) - - expect(config['validation']['tags']).to eq(['Dast Validation Tag']) + expect(config['validation']['tags']).to eq(['dast-validation-runner']) end end context 'when only untagged runners are available' do - let_it_be(:untagged_runner) { create(:ci_runner, :project, projects: [project], run_untagged: true) } - - before do - allow_next_instance_of(described_class) do |instance| - allow(instance).to receive(:available_runners_exists?).and_return(true) - allow(instance).to receive(:tagged_runners_available?).and_return(false) - allow(instance).to receive(:untagged_runners_available?).and_return(true) - end - end - it 'creates pipeline without tags configuration' do expect { subject }.to change { Ci::Pipeline.count }.by(1) @@ -170,39 +149,27 @@ it 'does not set validation entry in ci_configuration' do service = described_class.new(project: project, current_user: developer, params: { dast_site_validation: dast_site_validation }) - - allow(service).to receive(:tagged_runners_available?).and_return(false) - allow(service).to receive(:untagged_runners_available?).and_return(true) - config = service.send(:ci_configuration) - expect(config).not_to have_key('validation') end end context 'when both tagged and untagged runners are available' do - let(:ci_tag_2) { create(:ci_tag, name: 'Dast Validation Tag') } + let(:ci_tag_2) { create(:ci_tag, name: 'dast-validation-runner') } let(:tagged_runner_2) { create(:ci_runner, :project, projects: [project]) } - let(:untagged_runner) { create(:ci_runner, :project, projects: [project], run_untagged: true) } before do # Create the runner-tag association (avoid duplicates) unless tagged_runner_2.taggings.joins(:tag).where(tags: { name: ci_tag_2.name }).exists? create(:ci_runner_tagging, runner: tagged_runner_2, tag: ci_tag_2) end - # Override the mocks for this context - allow_next_instance_of(described_class) do |instance| - allow(instance).to receive(:available_runners_exists?).and_return(true) - allow(instance).to receive(:tagged_runners_available?).and_return(true) - allow(instance).to receive(:untagged_runners_available?).and_return(true) - end end it 'prioritizes tagged runners and sets tags in configuration' do service = described_class.new(project: project, current_user: developer, params: { dast_site_validation: dast_site_validation }) config = service.send(:ci_configuration) - expect(config['validation']['tags']).to eq(['Dast Validation Tag']) + expect(config['validation']['tags']).to eq(['dast-validation-runner']) end end @@ -213,10 +180,6 @@ mock_result = instance_double(ServiceResponse, success?: false) allow(instance).to receive(:execute).and_return(mock_result) end - # Mock runner availability to pass the initial check - allow_next_instance_of(described_class) do |instance| - allow(instance).to receive(:available_runners_exists?).and_return(true) - end end it 'transitions the dast_site_validation to a failure state', :aggregate_failures do -- GitLab From b005a319034e0eb1c72a08939a1d71e2dd6eff18 Mon Sep 17 00:00:00 2001 From: rossfuhrman Date: Mon, 8 Sep 2025 13:00:09 -0500 Subject: [PATCH 5/6] Address failing specs --- .../mutations/dast_site_validations/create_spec.rb | 12 ++++++++++++ .../mutations/dast_site_validations/create_spec.rb | 12 ++++++++++++ 2 files changed, 24 insertions(+) diff --git a/ee/spec/graphql/mutations/dast_site_validations/create_spec.rb b/ee/spec/graphql/mutations/dast_site_validations/create_spec.rb index 855388eeef6f15..1eca41a955ce4b 100644 --- a/ee/spec/graphql/mutations/dast_site_validations/create_spec.rb +++ b/ee/spec/graphql/mutations/dast_site_validations/create_spec.rb @@ -18,6 +18,18 @@ before do project.update!(ci_pipeline_variables_minimum_override_role: :developer) stub_licensed_features(security_on_demand_scans: true) + + allow(Ability).to receive(:allowed?).and_call_original + allow(Ability).to receive(:allowed?).with(current_user, :read_admin_cicd).and_return(true) + allow(Ability).to receive(:allowed?).with(current_user, :read_runners, project).and_return(true) + + allow_next_instance_of(AppSec::Dast::SiteValidations::RunnerService) do |instance| + allow(instance).to receive_messages( + available_runners_exists?: true, + tagged_runners_available?: false, + untagged_runners_available?: true + ) + end end specify { expect(described_class).to require_graphql_authorizations(:create_on_demand_dast_scan) } diff --git a/ee/spec/requests/api/graphql/mutations/dast_site_validations/create_spec.rb b/ee/spec/requests/api/graphql/mutations/dast_site_validations/create_spec.rb index b56b8c546d4e8b..ba3956a5754d97 100644 --- a/ee/spec/requests/api/graphql/mutations/dast_site_validations/create_spec.rb +++ b/ee/spec/requests/api/graphql/mutations/dast_site_validations/create_spec.rb @@ -28,6 +28,18 @@ it_behaves_like 'an on-demand scan mutation when user can run an on-demand scan' do before do project.update!(ci_pipeline_variables_minimum_override_role: :developer) + + allow(Ability).to receive(:allowed?).and_call_original + allow(Ability).to receive(:allowed?).with(current_user, :read_admin_cicd).and_return(true) + allow(Ability).to receive(:allowed?).with(current_user, :read_runners, project).and_return(true) + + allow_next_instance_of(AppSec::Dast::SiteValidations::RunnerService) do |instance| + allow(instance).to receive_messages( + available_runners_exists?: true, + tagged_runners_available?: false, + untagged_runners_available?: true + ) + end end it 'returns the dast_site_validation id' do -- GitLab From 3a9d8154feb56090eb310b4a6e4ce22c64227a74 Mon Sep 17 00:00:00 2001 From: rossfuhrman Date: Mon, 8 Sep 2025 13:09:38 -0500 Subject: [PATCH 6/6] Fix the whitespace --- ee/spec/graphql/mutations/dast_site_validations/create_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ee/spec/graphql/mutations/dast_site_validations/create_spec.rb b/ee/spec/graphql/mutations/dast_site_validations/create_spec.rb index 1eca41a955ce4b..6628283dc9f7b0 100644 --- a/ee/spec/graphql/mutations/dast_site_validations/create_spec.rb +++ b/ee/spec/graphql/mutations/dast_site_validations/create_spec.rb @@ -18,7 +18,7 @@ before do project.update!(ci_pipeline_variables_minimum_override_role: :developer) stub_licensed_features(security_on_demand_scans: true) - + allow(Ability).to receive(:allowed?).and_call_original allow(Ability).to receive(:allowed?).with(current_user, :read_admin_cicd).and_return(true) allow(Ability).to receive(:allowed?).with(current_user, :read_runners, project).and_return(true) -- GitLab