Commit 1fd3674a authored by Douglas Barbosa Alexandre's avatar Douglas Barbosa Alexandre

Merge branch...

Merge branch 'philipcunningham-add-backend-for-specifying-target-type-for-on-demand-294060' into 'master'

Add backend support for specifying target type [RUN ALL RSPEC] [RUN AS-IF-FOSS]

See merge request gitlab-org/gitlab!58723
parents 3659cda4 995f46a6
---
title: Add target_type column to dast_site_profiles database table
merge_request: 58723
author:
type: added
---
name: security_dast_site_profiles_api_option
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/58723
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/325130
milestone: '13.12'
type: development
group: group::dynamic analysis
default_enabled: false
# frozen_string_literal: true
class AddTypeToDastSiteProfile < ActiveRecord::Migration[6.0]
def change
add_column :dast_site_profiles, :target_type, :integer, limit: 2, default: 0, null: false
end
end
174d2c4dc57847060cb19405cc08fffd038c7bfbd4ad749e3e1eccf0e281230b
\ No newline at end of file
......@@ -11861,6 +11861,7 @@ CREATE TABLE dast_site_profiles (
auth_username_field text,
auth_password_field text,
auth_username text,
target_type smallint DEFAULT 0 NOT NULL,
CONSTRAINT check_5203110fee CHECK ((char_length(auth_username_field) <= 255)),
CONSTRAINT check_6cfab17b48 CHECK ((char_length(name) <= 255)),
CONSTRAINT check_c329dffdba CHECK ((char_length(auth_password_field) <= 255)),
......@@ -2117,6 +2117,7 @@ Represents a DAST Site Profile.
| `profileName` | [`String`](#string) | The name of the site profile. |
| `referencedInSecurityPolicies` | [`[String!]`](#string) | List of security policy names that are referencing given project. |
| `requestHeaders` | [`String`](#string) | Comma-separated list of request header names and values to be added to every request made by DAST. Will always return `null` if `security_dast_site_profiles_additional_fields` feature flag is disabled. |
| `targetType` | [`DastTargetTypeEnum`](#dasttargettypeenum) | The type of target to be scanned. Will always return `null` if `security_dast_site_profiles_api_option` feature flag is disabled. |
| `targetUrl` | [`String`](#string) | The URL of the target to be scanned. |
| `userPermissions` | [`DastSiteProfilePermissions!`](#dastsiteprofilepermissions) | Permissions for the current user on the resource. |
| `validationStatus` | [`DastSiteProfileValidationStatusEnum`](#dastsiteprofilevalidationstatusenum) | The current validation status of the site profile. |
......@@ -7871,6 +7872,13 @@ Status of a container repository.
| `HEADER` | Header validation. |
| `TEXT_FILE` | Text file validation. |
### `DastTargetTypeEnum`
| Value | Description |
| ----- | ----------- |
| `API` | API target. |
| `WEBSITE` | Website target. |
### `DataVisualizationColorEnum`
Color of the data visualization palette.
......
......@@ -23,6 +23,11 @@ module Mutations
required: false,
description: 'The URL of the target to be scanned.'
argument :target_type, Types::DastTargetTypeEnum,
required: false,
description: 'The type of target to be scanned. Will be ignored ' \
'if `security_dast_site_profiles_api_option` feature flag is disabled.'
argument :excluded_urls, [GraphQL::STRING_TYPE],
required: false,
default_value: [],
......@@ -45,13 +50,14 @@ module Mutations
def resolve(full_path:, profile_name:, target_url: nil, **params)
project = authorized_find!(full_path)
auth_params = feature_flagged(project, params[:auth], default: {})
auth_params = feature_flagged(project, :security_dast_site_profiles_additional_fields, params[:auth], default: {})
dast_site_profile_params = {
name: profile_name,
target_url: target_url,
excluded_urls: feature_flagged(project, params[:excluded_urls]),
request_headers: feature_flagged(project, params[:request_headers]),
target_type: feature_flagged(project, :security_dast_site_profiles_api_option, params[:target_type]),
excluded_urls: feature_flagged(project, :security_dast_site_profiles_additional_fields, params[:excluded_urls]),
request_headers: feature_flagged(project, :security_dast_site_profiles_additional_fields, params[:request_headers]),
auth_enabled: auth_params[:enabled],
auth_url: auth_params[:url],
auth_username_field: auth_params[:username_field],
......@@ -67,8 +73,8 @@ module Mutations
private
def feature_flagged(project, value, opts = {})
return opts[:default] unless Feature.enabled?(:security_dast_site_profiles_additional_fields, project, default_enabled: :yaml)
def feature_flagged(project, flag, value, opts = {})
return opts[:default] unless Feature.enabled?(flag, project, default_enabled: :yaml)
value || opts[:default]
end
......
......@@ -23,6 +23,10 @@ module Types
field :target_url, GraphQL::STRING_TYPE, null: true,
description: 'The URL of the target to be scanned.'
field :target_type, Types::DastTargetTypeEnum, null: true,
description: 'The type of target to be scanned. Will always return `null` ' \
'if `security_dast_site_profiles_api_option` feature flag is disabled.'
field :edit_path, GraphQL::STRING_TYPE, null: true,
description: 'Relative web path to the edit page of a site profile.'
......@@ -55,6 +59,12 @@ module Types
object.dast_site.url
end
def target_type
return unless Feature.enabled?(:security_dast_site_profiles_api_option, object.project, default_enabled: :yaml)
object.target_type
end
def edit_path
Rails.application.routes.url_helpers.edit_project_security_configuration_dast_scans_dast_site_profile_path(object.project, object)
end
......
# frozen_string_literal: true
module Types
class DastTargetTypeEnum < BaseEnum
value 'WEBSITE', description: 'Website target.', value: 'website'
value 'API', description: 'API target.', value: 'api'
end
end
......@@ -21,6 +21,8 @@ class DastSiteProfile < ApplicationRecord
after_destroy :cleanup_dast_site
enum target_type: { website: 0, api: 1 }
delegate :dast_site_validation, to: :dast_site, allow_nil: true
def status
......
......@@ -11,7 +11,9 @@ RSpec.describe Mutations::DastSiteProfiles::Create do
let(:profile_name) { SecureRandom.hex }
let(:target_url) { generate(:url) }
let(:excluded_urls) { ["#{target_url}/signout"] }
let(:request_headers) { 'Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:47.0) Gecko/20100101 Firefox/47.0' }
let_it_be(:request_headers) { 'Authorization: token' }
let_it_be(:target_type) { 'api' }
let(:auth) do
{
......@@ -40,6 +42,7 @@ RSpec.describe Mutations::DastSiteProfiles::Create do
full_path: full_path,
profile_name: profile_name,
target_url: target_url,
target_type: target_type,
excluded_urls: excluded_urls,
request_headers: request_headers,
auth: auth
......@@ -71,7 +74,8 @@ RSpec.describe Mutations::DastSiteProfiles::Create do
auth_username_field: auth[:username_field],
auth_password_field: auth[:password_field],
auth_username: auth[:username],
dast_site: have_attributes(url: target_url)
dast_site: have_attributes(url: target_url),
target_type: target_type
)
password_variable = dast_site_profile.secret_variables.find_by!(key: Dast::SiteProfileSecretVariable::PASSWORD)
......@@ -92,6 +96,7 @@ RSpec.describe Mutations::DastSiteProfiles::Create do
service_params = {
name: profile_name,
target_url: target_url,
target_type: target_type,
excluded_urls: excluded_urls,
request_headers: request_headers,
auth_enabled: auth[:enabled],
......@@ -146,6 +151,21 @@ RSpec.describe Mutations::DastSiteProfiles::Create do
end
end
context 'when the feature flag security_dast_site_profiles_api_option is disabled' do
before do
stub_feature_flags(security_dast_site_profiles_api_option: false)
end
it 'ignores target_type and uses the default target_type', :aggregate_failures do
subject
default_target_type = dast_site_profile.class.new.target_type
expect(default_target_type).not_to eq(target_type)
expect(dast_site_profile.target_type).to eq(default_target_type)
end
end
context 'when variable creation fails' do
it 'returns an error and the dast_site_profile' do
service = double(Dast::SiteProfileSecretVariables::CreateOrUpdateService)
......
......@@ -8,7 +8,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 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] }
before do
stub_licensed_features(security_on_demand_scans: true)
......@@ -39,6 +39,22 @@ RSpec.describe GitlabSchema.types['DastSiteProfile'] do
end
end
describe 'targetType field' do
context 'when the feature flag is disabled' do
it 'is nil' do
stub_feature_flags(security_dast_site_profiles_api_option: false)
expect(resolve_field(:target_type, object, current_user: user)).to be_nil
end
end
context 'when the feature flag is enabled' do
it 'is the target type' do
expect(resolve_field(:target_type, object, current_user: user)).to eq('website')
end
end
end
describe 'editPath field' do
it 'is the relative path to edit the dast_site_profile' do
path = "/#{project.full_path}/-/security/configuration/dast_scans/dast_site_profiles/#{object.id}/edit"
......
......@@ -122,6 +122,14 @@ RSpec.describe DastSiteProfile, type: :model do
end
end
describe 'enums' do
let(:target_types) do
{ website: 0, api: 1 }
end
it { is_expected.to define_enum_for(:target_type).with_values(**target_types) }
end
describe 'instance methods' do
describe '#destroy!' do
context 'when the associated dast_site has no dast_site_profiles' do
......
......@@ -16,6 +16,7 @@ RSpec.describe 'Creating a DAST Site Profile' do
full_path: full_path,
profile_name: profile_name,
target_url: target_url,
target_type: 'API',
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: {
......
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