Commit 40fa9ce8 authored by Marcos Rocha's avatar Marcos Rocha Committed by Luke Duncalfe

Add scan method to dast site profile GraphQL API

This MR adds the scan method to the dast site profile GraphQL API.

Changelog: added
MR: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/78745
EE: true
parent 31ab4415
......@@ -1858,6 +1858,7 @@ Input type: `DastSiteProfileCreateInput`
| <a id="mutationdastsiteprofilecreatefullpath"></a>`fullPath` | [`ID!`](#id) | Project the site profile belongs to. |
| <a id="mutationdastsiteprofilecreateprofilename"></a>`profileName` | [`String!`](#string) | Name of the site profile. |
| <a id="mutationdastsiteprofilecreaterequestheaders"></a>`requestHeaders` | [`String`](#string) | Comma-separated list of request header names and values to be added to every request made by DAST. |
| <a id="mutationdastsiteprofilecreatescanmethod"></a>`scanMethod` | [`DastScanMethodType`](#dastscanmethodtype) | Scan method by the scanner. Is not saved or updated if `dast_api_scanner` feature flag is disabled. |
| <a id="mutationdastsiteprofilecreatetargettype"></a>`targetType` | [`DastTargetTypeEnum`](#dasttargettypeenum) | Type of target to be scanned. |
| <a id="mutationdastsiteprofilecreatetargeturl"></a>`targetUrl` | [`String`](#string) | URL of the target to be scanned. |
......@@ -1903,6 +1904,7 @@ Input type: `DastSiteProfileUpdateInput`
| <a id="mutationdastsiteprofileupdateid"></a>`id` | [`DastSiteProfileID!`](#dastsiteprofileid) | ID of the site profile to be updated. |
| <a id="mutationdastsiteprofileupdateprofilename"></a>`profileName` | [`String!`](#string) | Name of the site profile. |
| <a id="mutationdastsiteprofileupdaterequestheaders"></a>`requestHeaders` | [`String`](#string) | Comma-separated list of request header names and values to be added to every request made by DAST. |
| <a id="mutationdastsiteprofileupdatescanmethod"></a>`scanMethod` | [`DastScanMethodType`](#dastscanmethodtype) | Scan method by the scanner. Is not saved or updated if `dast_api_scanner` feature flag is disabled. |
| <a id="mutationdastsiteprofileupdatetargettype"></a>`targetType` | [`DastTargetTypeEnum`](#dasttargettypeenum) | Type of target to be scanned. |
| <a id="mutationdastsiteprofileupdatetargeturl"></a>`targetUrl` | [`String`](#string) | URL of the target to be scanned. |
......@@ -9861,6 +9863,7 @@ Represents a DAST Site Profile.
| <a id="dastsiteprofileprofilename"></a>`profileName` | [`String`](#string) | Name of the site profile. |
| <a id="dastsiteprofilereferencedinsecuritypolicies"></a>`referencedInSecurityPolicies` | [`[String!]`](#string) | List of security policy names that are referencing given project. |
| <a id="dastsiteprofilerequestheaders"></a>`requestHeaders` | [`String`](#string) | Comma-separated list of request header names and values to be added to every request made by DAST. |
| <a id="dastsiteprofilescanmethod"></a>`scanMethod` | [`DastScanMethodType`](#dastscanmethodtype) | Scan method used by the scanner. Always returns `null` if `dast_api_scanner` feature flag is disabled. |
| <a id="dastsiteprofiletargettype"></a>`targetType` | [`DastTargetTypeEnum`](#dasttargettypeenum) | Type of target to be scanned. |
| <a id="dastsiteprofiletargeturl"></a>`targetUrl` | [`String`](#string) | URL of the target to be scanned. |
| <a id="dastsiteprofileuserpermissions"></a>`userPermissions` | [`DastSiteProfilePermissions!`](#dastsiteprofilepermissions) | Permissions for the current user on the resource. |
......@@ -17241,6 +17244,17 @@ Unit for the duration of Dast Profile Cadence.
| <a id="dastprofilecadenceunitweek"></a>`WEEK` | DAST Profile Cadence duration in weeks. |
| <a id="dastprofilecadenceunityear"></a>`YEAR` | DAST Profile Cadence duration in years. |
### `DastScanMethodType`
Scan method to be used by the scanner.
| Value | Description |
| ----- | ----------- |
| <a id="dastscanmethodtypehar"></a>`HAR` | HAR scan method. |
| <a id="dastscanmethodtypeopenapi"></a>`OPENAPI` | OpenAPI scan method. |
| <a id="dastscanmethodtypepostman_collection"></a>`POSTMAN_COLLECTION` | Postman scan method. |
| <a id="dastscanmethodtypewebsite"></a>`WEBSITE` | Website scan method. |
### `DastScanTypeEnum`
| Value | Description |
......@@ -22,6 +22,11 @@ module Mutations
required: false,
description: 'Type of target to be scanned.'
argument :scan_method, Types::Dast::ScanMethodTypeEnum,
required: false,
description: 'Scan method by the scanner. Is not saved or updated ' \
'if `dast_api_scanner` feature flag is disabled.'
argument :request_headers, GraphQL::Types::String,
required: false,
description: 'Comma-separated list of request header names and values to be ' \
......
......@@ -42,6 +42,10 @@ module Mutations
auth_password: auth_params[:password]
}.compact
if Feature.enabled?(:dast_api_scanner, project, default_enabled: :yaml)
dast_site_profile_params[:scan_method] = params[:scan_method]
end
result = ::AppSec::Dast::SiteProfiles::CreateService.new(project, current_user).execute(**dast_site_profile_params)
{ id: result.payload.try(:to_global_id), errors: result.errors }
......
......@@ -49,6 +49,10 @@ module Mutations
auth_password: auth_params[:password]
}.compact
if Feature.enabled?(:dast_api_scanner, dast_site_profile.project, default_enabled: :yaml)
dast_site_profile_params[:scan_method] = params[:scan_method]
end
result = ::AppSec::Dast::SiteProfiles::UpdateService.new(dast_site_profile.project, current_user).execute(**dast_site_profile_params)
{ id: result.payload.try(:to_global_id), errors: result.errors }
......
# frozen_string_literal: true
module Types
module Dast
class ScanMethodTypeEnum < BaseEnum
graphql_name 'DastScanMethodType'
description 'Scan method to be used by the scanner.'
value 'WEBSITE', description: 'Website scan method.', value: 'site'
value 'OPENAPI', description: 'OpenAPI scan method.', value: 'openapi'
value 'HAR', description: 'HAR scan method.', value: 'har'
value 'POSTMAN_COLLECTION', description: 'Postman scan method.', value: 'postman'
end
end
end
......@@ -50,6 +50,10 @@ module Types
calls_gitaly: true,
description: 'List of security policy names that are referencing given project.'
field :scan_method, Types::Dast::ScanMethodTypeEnum, null: true,
description: 'Scan method used by the scanner. Always returns `null` ' \
'if `dast_api_scanner` feature flag is disabled.'
def target_url
object.dast_site.url
end
......@@ -72,5 +76,11 @@ module Types
object
)
end
def scan_method
return unless Feature.enabled?(:dast_api_scanner, object.project, default_enabled: :yaml)
object.scan_method
end
end
end
......@@ -14,6 +14,7 @@ RSpec.describe Mutations::DastSiteProfiles::Create do
let_it_be(:request_headers) { 'Authorization: token' }
let_it_be(:target_type) { 'api' }
let_it_be(:scan_method) { 'openapi' }
let(:auth) do
{
......@@ -45,7 +46,8 @@ RSpec.describe Mutations::DastSiteProfiles::Create do
target_type: target_type,
excluded_urls: excluded_urls,
request_headers: request_headers,
auth: auth
auth: auth,
scan_method: scan_method
)
end
......@@ -63,6 +65,28 @@ RSpec.describe Mutations::DastSiteProfiles::Create do
project.add_developer(user)
end
context 'when the feature flag dast_api_scanner is disabled' do
before do
stub_feature_flags(dast_api_scanner: false)
end
context 'when the target_type is api' do
it 'creates a dast_site_profile with the default value for the scan_method' do
dast_site_profile = subject[:id].find
expect(dast_site_profile.scan_method).to eq('openapi')
end
end
context 'when the target_type is website' do
let_it_be(:target_type) { 'website' }
it 'creates a dast_site_profile with the default value for the scan_method' do
dast_site_profile = subject[:id].find
expect(dast_site_profile.scan_method).to eq('site')
end
end
end
it 'creates a dast_site_profile and dast_site_profile_secret_variables', :aggregate_failures do
dast_site_profile = subject[:id].find
......@@ -75,7 +99,8 @@ RSpec.describe Mutations::DastSiteProfiles::Create do
auth_password_field: auth[:password_field],
auth_username: auth[:username],
dast_site: have_attributes(url: target_url),
target_type: target_type
target_type: target_type,
scan_method: scan_method
)
password_variable = dast_site_profile.secret_variables.find_by!(key: Dast::SiteProfileSecretVariable::PASSWORD)
......@@ -99,6 +124,7 @@ RSpec.describe Mutations::DastSiteProfiles::Create do
target_type: target_type,
excluded_urls: excluded_urls,
request_headers: request_headers,
scan_method: scan_method,
auth_enabled: auth[:enabled],
auth_url: auth[:url],
auth_username_field: auth[:username_field],
......
......@@ -13,6 +13,7 @@ RSpec.describe Mutations::DastSiteProfiles::Update do
let(:new_excluded_urls) { ["#{new_target_url}/signout"] }
let(:new_request_headers) { "Authorization: Bearer #{SecureRandom.hex}" }
let(:new_target_type) { 'api' }
let(:new_scan_method) { 'postman' }
let(:new_auth) do
{
......@@ -42,6 +43,7 @@ RSpec.describe Mutations::DastSiteProfiles::Update do
target_type: new_target_type,
excluded_urls: new_excluded_urls,
request_headers: new_request_headers,
scan_method: new_scan_method,
auth: new_auth
)
end
......@@ -63,6 +65,7 @@ RSpec.describe Mutations::DastSiteProfiles::Update do
target_type: new_target_type,
excluded_urls: new_excluded_urls,
request_headers: new_request_headers,
scan_method: new_scan_method,
auth_enabled: new_auth[:enabled],
auth_url: new_auth[:url],
auth_username_field: new_auth[:username_field],
......@@ -88,6 +91,7 @@ RSpec.describe Mutations::DastSiteProfiles::Update do
auth_username_field: new_auth[:username_field],
auth_password_field: new_auth[:password_field],
auth_username: new_auth[:username],
scan_method: new_scan_method,
dast_site: have_attributes(url: new_target_url)
)
......@@ -143,6 +147,18 @@ RSpec.describe Mutations::DastSiteProfiles::Update do
expect(subject).to include(errors: ['Oops'])
end
end
context 'when the feature flag dast_api_scanner is disabled' do
before do
stub_feature_flags(dast_api_scanner: false)
end
it 'does not update the scan_method and uses the default value according to the target_type' do
dast_site_profile = subject[:id].find
expect(dast_site_profile.scan_method).to eq('openapi')
end
end
end
end
end
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe GitlabSchema.types['DastScanMethodType'] do
it 'exposes all alert field names' do
expect(described_class.values.keys).to match_array(%w(WEBSITE OPENAPI HAR POSTMAN_COLLECTION))
end
end
......@@ -9,7 +9,7 @@ RSpec.describe GitlabSchema.types['DastSiteProfile'] do
let_it_be(:project) { create(:project) }
let_it_be(:user) { create(:user, developer_projects: [project]) }
let_it_be(:object, reload: true) { create(:dast_site_profile, project: project) }
let_it_be(:fields) { %i[id profileName targetUrl targetType editPath excludedUrls requestHeaders validationStatus userPermissions normalizedTargetUrl auth referencedInSecurityPolicies] }
let_it_be(:fields) { %i[id profileName targetUrl targetType editPath excludedUrls requestHeaders validationStatus userPermissions normalizedTargetUrl auth referencedInSecurityPolicies scanMethod] }
before do
stub_licensed_features(security_on_demand_scans: true)
......@@ -105,6 +105,22 @@ RSpec.describe GitlabSchema.types['DastSiteProfile'] do
end
end
describe 'scan_method field' do
context 'when the feature flag is disabled' do
it 'resolves nil' do
stub_feature_flags(dast_api_scanner: false)
expect(resolve_field(:scan_method, object, current_user: user)).to eq(nil)
end
end
context 'when the feature flag is enabled' do
it 'is the scan method' do
expect(resolve_field(:scan_method, object, current_user: user)).to eq('site')
end
end
end
describe 'dast_site_profiles' do
subject(:response) do
GitlabSchema.execute(
......
......@@ -20,6 +20,7 @@ RSpec.describe 'Creating a DAST Site Profile' do
profile_name: profile_name,
target_url: target_url,
target_type: 'API',
scan_method: 'OPENAPI',
excluded_urls: ["#{target_url}/logout"],
request_headers: 'Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:47.0) Gecko/20100101 Firefox/47.0',
auth: {
......
......@@ -22,6 +22,7 @@ RSpec.describe 'Creating a DAST Site Profile' do
profile_name: new_profile_name,
target_url: new_target_url,
target_type: 'API',
scan_method: 'OPENAPI',
excluded_urls: ["#{new_target_url}/signout"],
request_headers: 'Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:47.0) Gecko/20100101 Firefox/47.0',
auth: {
......
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