Commit 1460dd29 authored by Marcos Rocha's avatar Marcos Rocha Committed by Mayra Cabrera

Filter Dast Profiles with Schedule

parent 5e38e52a
...@@ -12644,7 +12644,6 @@ Represents vulnerability finding of a security report on the pipeline. ...@@ -12644,7 +12644,6 @@ Represents vulnerability finding of a security report on the pipeline.
| <a id="projectcontainerregistryenabled"></a>`containerRegistryEnabled` | [`Boolean`](#boolean) | Indicates if Container Registry is enabled for the current user. | | <a id="projectcontainerregistryenabled"></a>`containerRegistryEnabled` | [`Boolean`](#boolean) | Indicates if Container Registry is enabled for the current user. |
| <a id="projectcontainerrepositoriescount"></a>`containerRepositoriesCount` | [`Int!`](#int) | Number of container repositories in the project. | | <a id="projectcontainerrepositoriescount"></a>`containerRepositoriesCount` | [`Int!`](#int) | Number of container repositories in the project. |
| <a id="projectcreatedat"></a>`createdAt` | [`Time`](#time) | Timestamp of the project creation. | | <a id="projectcreatedat"></a>`createdAt` | [`Time`](#time) | Timestamp of the project creation. |
| <a id="projectdastprofiles"></a>`dastProfiles` | [`DastProfileConnection`](#dastprofileconnection) | DAST Profiles associated with the project. (see [Connections](#connections)) |
| <a id="projectdastscannerprofiles"></a>`dastScannerProfiles` | [`DastScannerProfileConnection`](#dastscannerprofileconnection) | DAST scanner profiles associated with the project. (see [Connections](#connections)) | | <a id="projectdastscannerprofiles"></a>`dastScannerProfiles` | [`DastScannerProfileConnection`](#dastscannerprofileconnection) | DAST scanner profiles associated with the project. (see [Connections](#connections)) |
| <a id="projectdastsiteprofiles"></a>`dastSiteProfiles` | [`DastSiteProfileConnection`](#dastsiteprofileconnection) | DAST Site Profiles associated with the project. (see [Connections](#connections)) | | <a id="projectdastsiteprofiles"></a>`dastSiteProfiles` | [`DastSiteProfileConnection`](#dastsiteprofileconnection) | DAST Site Profiles associated with the project. (see [Connections](#connections)) |
| <a id="projectdescription"></a>`description` | [`String`](#string) | Short description of the project. | | <a id="projectdescription"></a>`description` | [`String`](#string) | Short description of the project. |
...@@ -12882,8 +12881,25 @@ Returns [`DastProfile`](#dastprofile). ...@@ -12882,8 +12881,25 @@ Returns [`DastProfile`](#dastprofile).
| Name | Type | Description | | Name | Type | Description |
| ---- | ---- | ----------- | | ---- | ---- | ----------- |
| <a id="projectdastprofilehasdastprofileschedule"></a>`hasDastProfileSchedule` | [`Boolean`](#boolean) | Filter DAST Profiles by whether or not they have a schedule. Will be ignored if `dast_view_scans` feature flag is disabled. |
| <a id="projectdastprofileid"></a>`id` | [`DastProfileID!`](#dastprofileid) | ID of the DAST Profile. | | <a id="projectdastprofileid"></a>`id` | [`DastProfileID!`](#dastprofileid) | ID of the DAST Profile. |
##### `Project.dastProfiles`
DAST Profiles associated with the project.
Returns [`DastProfileConnection`](#dastprofileconnection).
This field returns a [connection](#connections). It accepts the
four standard [pagination arguments](#connection-pagination-arguments):
`before: String`, `after: String`, `first: Int`, `last: Int`.
###### Arguments
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="projectdastprofileshasdastprofileschedule"></a>`hasDastProfileSchedule` | [`Boolean`](#boolean) | Filter DAST Profiles by whether or not they have a schedule. Will be ignored if `dast_view_scans` feature flag is disabled. |
##### `Project.dastSiteProfile` ##### `Project.dastSiteProfile`
DAST Site Profile associated with the project. DAST Site Profile associated with the project.
......
...@@ -12,6 +12,7 @@ module Dast ...@@ -12,6 +12,7 @@ module Dast
relation = default_relation relation = default_relation
relation = by_id(relation) relation = by_id(relation)
relation = by_project(relation) relation = by_project(relation)
relation = has_schedule?(relation)
sort(relation) sort(relation)
end end
...@@ -38,6 +39,12 @@ module Dast ...@@ -38,6 +39,12 @@ module Dast
relation.by_project_id(params[:project_id]) relation.by_project_id(params[:project_id])
end end
def has_schedule?(relation)
return relation if params[:has_dast_profile_schedule].nil?
relation.with_schedule(params[:has_dast_profile_schedule])
end
# rubocop: disable CodeReuse/ActiveRecord # rubocop: disable CodeReuse/ActiveRecord
def sort(relation) def sort(relation)
relation.order(DEFAULT_SORT) relation.order(DEFAULT_SORT)
......
...@@ -10,6 +10,10 @@ module Resolvers ...@@ -10,6 +10,10 @@ module Resolvers
type ::Types::Dast::ProfileType.connection_type, null: true type ::Types::Dast::ProfileType.connection_type, null: true
argument :has_dast_profile_schedule, ::GraphQL::Types::Boolean,
required: false,
description: 'Filter DAST Profiles by whether or not they have a schedule. Will be ignored if `dast_view_scans` feature flag is disabled.'
when_single do when_single do
argument :id, ::Types::GlobalIDType[::Dast::Profile], argument :id, ::Types::GlobalIDType[::Dast::Profile],
required: true, required: true,
...@@ -17,6 +21,7 @@ module Resolvers ...@@ -17,6 +21,7 @@ module Resolvers
end end
def resolve_with_lookahead(**args) def resolve_with_lookahead(**args)
args.delete(:has_dast_profile_schedule) unless Feature.enabled?(:dast_view_scans, project, default_enabled: :yaml)
apply_lookahead(find_dast_profiles(args)) apply_lookahead(find_dast_profiles(args))
end end
...@@ -41,6 +46,8 @@ module Resolvers ...@@ -41,6 +46,8 @@ module Resolvers
params[:id] = ::Types::GlobalIDType[::Dast::Profile].coerce_isolated_input(args[:id]).model_id params[:id] = ::Types::GlobalIDType[::Dast::Profile].coerce_isolated_input(args[:id]).model_id
end end
params[:has_dast_profile_schedule] = args[:has_dast_profile_schedule] if args.has_key?(:has_dast_profile_schedule)
::Dast::ProfilesFinder.new(params).execute ::Dast::ProfilesFinder.new(params).execute
end end
end end
......
...@@ -27,6 +27,10 @@ module Dast ...@@ -27,6 +27,10 @@ module Dast
where(project_id: project_id) where(project_id: project_id)
end end
scope :with_schedule, -> (has_dast_profile_schedule) do
has_dast_profile_schedule ? joins(:dast_profile_schedule) : where.missing(:dast_profile_schedule)
end
delegate :secret_ci_variables, to: :dast_site_profile delegate :secret_ci_variables, to: :dast_site_profile
sanitizes! :name, :description sanitizes! :name, :description
......
...@@ -8,6 +8,7 @@ RSpec.describe Dast::ProfilesFinder do ...@@ -8,6 +8,7 @@ RSpec.describe Dast::ProfilesFinder do
let_it_be(:dast_profile1) { create(:dast_profile, project: project1) } let_it_be(:dast_profile1) { create(:dast_profile, project: project1) }
let_it_be(:dast_profile2) { create(:dast_profile, project: project2) } let_it_be(:dast_profile2) { create(:dast_profile, project: project2) }
let_it_be(:dast_profile3) { create(:dast_profile, project: project1) } let_it_be(:dast_profile3) { create(:dast_profile, project: project1) }
let_it_be(:dast_profile_schedule) { create(:dast_profile_schedule, project: project1, dast_profile: dast_profile3)}
let(:params) { {} } let(:params) { {} }
...@@ -40,6 +41,24 @@ RSpec.describe Dast::ProfilesFinder do ...@@ -40,6 +41,24 @@ RSpec.describe Dast::ProfilesFinder do
end end
end end
context 'filtering by has_schedule?' do
let(:params) { { has_dast_profile_schedule: true } }
context 'when has_dast_profile_schedule is true' do
it 'returns the dast_profiles with schedule' do
expect(subject).to contain_exactly(dast_profile3)
end
end
end
context 'filtering by *' do
let(:params) { { id: dast_profile3.id, project_id: project1.id, has_dast_profile_schedule: true } }
it 'returns the matching dast_profile' do
expect(subject).to contain_exactly(dast_profile3)
end
end
context 'when the dast_profile does not exist' do context 'when the dast_profile does not exist' do
let(:params) { { project_id: 0 } } let(:params) { { project_id: 0 } }
......
...@@ -102,6 +102,33 @@ RSpec.describe Dast::Profile, type: :model do ...@@ -102,6 +102,33 @@ RSpec.describe Dast::Profile, type: :model do
end end
end end
end end
describe 'with_schedule' do
let_it_be(:another_dast_profile) { create(:dast_profile) }
let_it_be(:dast_profile_schedule) { create(:dast_profile_schedule, project: project, dast_profile: another_dast_profile) }
context 'when has_dast_profile_schedule is true' do
it 'includes the dast_profile with schedule' do
result = described_class.with_schedule(true)
aggregate_failures do
expect(result).to include(another_dast_profile)
expect(result).not_to include(subject)
end
end
end
context 'when has_dast_profile_schedule is false' do
it 'includes the dast_profile without schedule' do
result = described_class.with_schedule(false)
aggregate_failures do
expect(result).to include(subject)
expect(result).not_to include(another_dast_profile)
end
end
end
end
end end
describe 'instance methods' do describe 'instance methods' do
......
...@@ -11,6 +11,14 @@ RSpec.describe 'Query.project(fullPath).dastProfiles' do ...@@ -11,6 +11,14 @@ RSpec.describe 'Query.project(fullPath).dastProfiles' do
let_it_be(:dast_profile2) { create(:dast_profile, project: project) } let_it_be(:dast_profile2) { create(:dast_profile, project: project) }
let_it_be(:dast_profile3) { create(:dast_profile, project: project) } let_it_be(:dast_profile3) { create(:dast_profile, project: project) }
let_it_be(:dast_profile4) { create(:dast_profile, project: project) } let_it_be(:dast_profile4) { create(:dast_profile, project: project) }
let_it_be(:dast_profile5) { create(:dast_profile, project: project) }
let_it_be(:dast_profile_schedule) { create(:dast_profile_schedule, project: project, dast_profile: dast_profile5)}
let(:all_records) do
[dast_profile5, dast_profile4, dast_profile3, dast_profile2, dast_profile1].map { |validation| global_id_of(validation) }
end
let(:query_args) { {} }
let(:query) do let(:query) do
fields = all_graphql_fields_for('DastProfile') fields = all_graphql_fields_for('DastProfile')
...@@ -18,7 +26,7 @@ RSpec.describe 'Query.project(fullPath).dastProfiles' do ...@@ -18,7 +26,7 @@ RSpec.describe 'Query.project(fullPath).dastProfiles' do
graphql_query_for( graphql_query_for(
:project, :project,
{ full_path: project.full_path }, { full_path: project.full_path },
query_nodes(:dast_profiles, fields) query_nodes(:dast_profiles, fields, args: query_args)
) )
end end
...@@ -65,13 +73,18 @@ RSpec.describe 'Query.project(fullPath).dastProfiles' do ...@@ -65,13 +73,18 @@ RSpec.describe 'Query.project(fullPath).dastProfiles' do
dast_profiles.map { |dast_profile| dast_profile['id'] } dast_profiles.map { |dast_profile| dast_profile['id'] }
end end
shared_examples 'returns all dastProfiles' do
it 'returns all dastProfiles', :aggregate_failures do
subject
expect(graphql_data_at(:project, :dast_profiles, :nodes).count).to eq(5)
expect(graphql_data_at(:project, :dast_profiles, :nodes, :id)).to contain_exactly(*all_records)
end
end
it_behaves_like 'sorted paginated query' do it_behaves_like 'sorted paginated query' do
let(:sort_param) { nil } let(:sort_param) { nil }
let(:first_param) { 3 } let(:first_param) { 3 }
let(:all_records) do
[dast_profile4, dast_profile3, dast_profile2, dast_profile1].map { |validation| global_id_of(validation)}
end
end end
it 'includes branch information' do it 'includes branch information' do
...@@ -95,6 +108,36 @@ RSpec.describe 'Query.project(fullPath).dastProfiles' do ...@@ -95,6 +108,36 @@ RSpec.describe 'Query.project(fullPath).dastProfiles' do
expect { subject }.not_to exceed_query_limit(control) expect { subject }.not_to exceed_query_limit(control)
end end
context 'when `dast_view_scans` feature flag is disabled' do
before do
stub_feature_flags(dast_view_scans: false)
end
context 'when hasDastProfileSchedule is false' do
let(:query_args) { { hasDastProfileSchedule: false } }
include_examples 'returns all dastProfiles'
end
context 'when hasDastProfileSchedule is true' do
let(:query_args) { { hasDastProfileSchedule: true } }
include_examples 'returns all dastProfiles'
end
end
context 'when `dast_view_scans` feature flag is enabled' do
context 'when hasDastProfileSchedule is true' do
let(:query_args) { { hasDastProfileSchedule: true } }
it 'returns all dastProfiles with a schedule' do
subject
expect(graphql_data_at(:project, :dast_profiles, :nodes, :id)).to contain_exactly(dast_profile5.to_global_id.to_s)
end
end
end
end end
def pagination_query(arguments) def pagination_query(arguments)
......
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