Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
7942afee
Commit
7942afee
authored
Apr 22, 2021
by
Dheeraj Joshi
Committed by
Alex Kalderimis
Apr 22, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add option to specify target type for DAST Profiles
parent
69bd1adf
Changes
12
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
157 additions
and
22 deletions
+157
-22
ee/app/assets/javascripts/on_demand_scans/components/on_demand_scans_form.vue
...ripts/on_demand_scans/components/on_demand_scans_form.vue
+12
-1
ee/app/assets/javascripts/security_configuration/dast_profiles/graphql/dast_site_profiles.query.graphql
...on/dast_profiles/graphql/dast_site_profiles.query.graphql
+1
-0
ee/app/assets/javascripts/security_configuration/dast_site_profiles_form/components/dast_site_profile_form.vue
..._site_profiles_form/components/dast_site_profile_form.vue
+42
-7
ee/app/assets/javascripts/security_configuration/dast_site_profiles_form/constants.js
...curity_configuration/dast_site_profiles_form/constants.js
+7
-0
ee/app/controllers/projects/on_demand_scans_controller.rb
ee/app/controllers/projects/on_demand_scans_controller.rb
+1
-0
ee/app/controllers/projects/security/dast_site_profiles_controller.rb
...ollers/projects/security/dast_site_profiles_controller.rb
+2
-0
ee/spec/frontend/on_demand_scans/components/on_demand_scans_form_spec.js
...d/on_demand_scans/components/on_demand_scans_form_spec.js
+3
-0
ee/spec/frontend/on_demand_scans/components/profile_selector/site_profile_selector_spec.js
...components/profile_selector/site_profile_selector_spec.js
+1
-0
ee/spec/frontend/on_demand_scans/mocks/mock_data.js
ee/spec/frontend/on_demand_scans/mocks/mock_data.js
+3
-0
ee/spec/frontend/security_configuration/dast_site_profiles_form/components/dast_site_profile_form_spec.js
...e_profiles_form/components/dast_site_profile_form_spec.js
+75
-14
ee/spec/requests/projects/security/dast_site_profiles_controller_spec.rb
...s/projects/security/dast_site_profiles_controller_spec.rb
+1
-0
locale/gitlab.pot
locale/gitlab.pot
+9
-0
No files found.
ee/app/assets/javascripts/on_demand_scans/components/on_demand_scans_form.vue
View file @
7942afee
...
...
@@ -18,7 +18,10 @@ import {
SCAN_TYPE_LABEL
,
SCAN_TYPE
,
}
from
'
ee/security_configuration/dast_scanner_profiles/constants
'
;
import
{
EXCLUDED_URLS_SEPARATOR
}
from
'
ee/security_configuration/dast_site_profiles_form/constants
'
;
import
{
EXCLUDED_URLS_SEPARATOR
,
TARGET_TYPES
,
}
from
'
ee/security_configuration/dast_site_profiles_form/constants
'
;
import
{
DAST_SITE_VALIDATION_STATUS
}
from
'
ee/security_configuration/dast_site_validation/constants
'
;
import
{
initFormField
}
from
'
ee/security_configuration/utils
'
;
import
{
convertToGraphQLId
}
from
'
~/graphql_shared/utils
'
;
...
...
@@ -234,6 +237,9 @@ export default {
hasExcludedUrls
()
{
return
this
.
selectedSiteProfile
.
excludedUrls
?.
length
>
0
;
},
targetTypeValue
()
{
return
TARGET_TYPES
[
this
.
selectedSiteProfile
.
targetType
].
text
;
},
storageKey
()
{
return
`
${
this
.
projectPath
}
/
${
ON_DEMAND_SCANS_STORAGE_KEY
}
`
;
},
...
...
@@ -501,6 +507,11 @@ export default {
:label="s__('DastProfiles|Target URL')"
:value="selectedSiteProfile.targetUrl"
/>
<profile-selector-summary-cell
v-if=
"glFeatures.securityDastSiteProfilesApiOption"
:label=
"s__('DastProfiles|Site type')"
:value=
"targetTypeValue"
/>
</div>
<template
v-if=
"glFeatures.securityDastSiteProfilesAdditionalFields"
>
<template
v-if=
"selectedSiteProfile.auth.enabled"
>
...
...
ee/app/assets/javascripts/security_configuration/dast_profiles/graphql/dast_site_profiles.query.graphql
View file @
7942afee
...
...
@@ -14,6 +14,7 @@ query DastSiteProfiles($fullPath: ID!, $after: String, $before: String, $first:
profileName
normalizedTargetUrl
targetUrl
targetType
editPath
validationStatus
referencedInSecurityPolicies
...
...
ee/app/assets/javascripts/security_configuration/dast_site_profiles_form/components/dast_site_profile_form.vue
View file @
7942afee
...
...
@@ -8,6 +8,7 @@ import {
GlModal
,
GlFormTextarea
,
GlFormText
,
GlFormRadioGroup
,
}
from
'
@gitlab/ui
'
;
import
*
as
Sentry
from
'
@sentry/browser
'
;
import
{
isEqual
}
from
'
lodash
'
;
...
...
@@ -23,6 +24,7 @@ import {
EXCLUDED_URLS_SEPARATOR
,
REDACTED_PASSWORD
,
REDACTED_REQUEST_HEADERS
,
TARGET_TYPES
,
}
from
'
../constants
'
;
import
dastSiteProfileCreateMutation
from
'
../graphql/dast_site_profile_create.mutation.graphql
'
;
import
dastSiteProfileUpdateMutation
from
'
../graphql/dast_site_profile_update.mutation.graphql
'
;
...
...
@@ -41,6 +43,7 @@ export default {
DastSiteAuthSection
,
GlFormText
,
tooltipIcon
,
GlFormRadioGroup
,
},
directives
:
{
validation
:
validation
(),
...
...
@@ -63,8 +66,14 @@ export default {
},
},
data
()
{
const
{
name
=
''
,
targetUrl
=
''
,
excludedUrls
=
[],
requestHeaders
=
''
,
auth
=
{}
}
=
this
.
siteProfile
||
{};
const
{
name
=
''
,
targetUrl
=
''
,
excludedUrls
=
[],
requestHeaders
=
''
,
auth
=
{},
targetType
=
TARGET_TYPES
.
WEBSITE
.
value
,
}
=
this
.
siteProfile
||
{};
const
form
=
{
state
:
false
,
...
...
@@ -82,6 +91,7 @@ export default {
required
:
false
,
skipValidation
:
true
,
}),
targetType
:
initFormField
({
value
:
targetType
,
skipValidation
:
true
}),
},
};
...
...
@@ -95,6 +105,7 @@ export default {
token
:
null
,
errorMessage
:
''
,
errors
:
[],
targetTypesOptions
:
Object
.
values
(
TARGET_TYPES
),
};
},
computed
:
{
...
...
@@ -156,6 +167,12 @@ export default {
}
return
authFields
;
},
isTargetAPI
()
{
return
(
this
.
glFeatures
.
securityDastSiteProfilesApiOption
&&
this
.
form
.
fields
.
targetType
.
value
===
TARGET_TYPES
.
API
.
value
);
},
},
methods
:
{
onSubmit
()
{
...
...
@@ -173,9 +190,13 @@ export default {
this
.
hideErrors
();
const
{
errorMessage
}
=
this
.
i18n
;
const
{
profileName
,
targetUrl
,
requestHeaders
,
excludedUrls
}
=
serializeFormObject
(
this
.
form
.
fields
,
);
const
{
profileName
,
targetUrl
,
targetType
,
requestHeaders
,
excludedUrls
,
}
=
serializeFormObject
(
this
.
form
.
fields
);
const
variables
=
{
input
:
{
...
...
@@ -183,8 +204,11 @@ export default {
...(
this
.
isEdit
?
{
id
:
this
.
siteProfile
.
id
}
:
{}),
profileName
,
targetUrl
,
...(
this
.
glFeatures
.
securityDastSiteProfilesApiOption
&&
{
targetType
,
}),
...(
this
.
glFeatures
.
securityDastSiteProfilesAdditionalFields
&&
{
auth
:
this
.
serializedAuthFields
,
...(
!
this
.
isTargetAPI
&&
{
auth
:
this
.
serializedAuthFields
})
,
...(
excludedUrls
&&
{
excludedUrls
:
this
.
parsedExcludedUrls
,
}),
...
...
@@ -314,6 +338,17 @@ export default {
<hr
class=
"gl-border-gray-100"
/>
<gl-form-group
v-if=
"glFeatures.securityDastSiteProfilesApiOption"
:label=
"s__('DastProfiles|Site type')"
>
<gl-form-radio-group
v-model=
"form.fields.targetType.value"
:options=
"targetTypesOptions"
data-testid=
"site-type-option"
/>
</gl-form-group>
<gl-form-group
data-testid=
"target-url-input-group"
:invalid-feedback=
"form.fields.targetUrl.feedback"
...
...
@@ -381,7 +416,7 @@ export default {
</gl-form-group>
<dast-site-auth-section
v-if=
"glFeatures.securityDastSiteProfilesAdditionalFields"
v-if=
"glFeatures.securityDastSiteProfilesAdditionalFields
&& !isTargetAPI
"
v-model=
"authSection"
:disabled=
"isPolicyProfile"
:show-validation=
"form.showValidation"
...
...
ee/app/assets/javascripts/security_configuration/dast_site_profiles_form/constants.js
View file @
7942afee
import
{
s__
}
from
'
~/locale
'
;
export
const
MAX_CHAR_LIMIT_EXCLUDED_URLS
=
2048
;
export
const
MAX_CHAR_LIMIT_REQUEST_HEADERS
=
2048
;
export
const
EXCLUDED_URLS_SEPARATOR
=
'
,
'
;
export
const
REDACTED_PASSWORD
=
'
••••••••
'
;
export
const
REDACTED_REQUEST_HEADERS
=
'
••••••••
'
;
export
const
TARGET_TYPES
=
{
WEBSITE
:
{
value
:
'
WEBSITE
'
,
text
:
s__
(
'
DastProfiles|Website
'
)
},
API
:
{
value
:
'
API
'
,
text
:
s__
(
'
DastProfiles|Rest API
'
)
},
};
ee/app/controllers/projects/on_demand_scans_controller.rb
View file @
7942afee
...
...
@@ -6,6 +6,7 @@ module Projects
before_action
do
push_frontend_feature_flag
(
:security_dast_site_profiles_additional_fields
,
@project
,
default_enabled: :yaml
)
push_frontend_feature_flag
(
:security_dast_site_profiles_api_option
,
@project
,
default_enabled: :yaml
)
end
before_action
:authorize_read_on_demand_scans!
,
only: :index
...
...
ee/app/controllers/projects/security/dast_site_profiles_controller.rb
View file @
7942afee
...
...
@@ -9,6 +9,7 @@ module Projects
before_action
do
authorize_read_on_demand_scans!
push_frontend_feature_flag
(
:security_dast_site_profiles_additional_fields
,
@project
,
default_enabled: :yaml
)
push_frontend_feature_flag
(
:security_dast_site_profiles_api_option
,
@project
,
default_enabled: :yaml
)
end
feature_category
:dynamic_application_security_testing
...
...
@@ -26,6 +27,7 @@ module Projects
id
name: profileName
targetUrl
targetType
excludedUrls
requestHeaders
auth { enabled url username usernameField password passwordField }
...
...
ee/spec/frontend/on_demand_scans/components/on_demand_scans_form_spec.js
View file @
7942afee
...
...
@@ -559,6 +559,7 @@ describe('OnDemandScansForm', () => {
provide
:
{
glFeatures
:
{
securityDastSiteProfilesAdditionalFields
:
true
,
securityDastSiteProfilesApiOption
:
true
,
},
},
});
...
...
@@ -569,6 +570,7 @@ describe('OnDemandScansForm', () => {
const
summary
=
wrapper
.
find
(
SiteProfileSelector
).
text
();
const
defaultPassword
=
'
••••••••
'
;
const
defaultRequestHeaders
=
'
[Redacted]
'
;
const
defaultSiteType
=
'
Website
'
;
expect
(
summary
).
toMatch
(
authEnabledProfile
.
targetUrl
);
expect
(
summary
).
toMatch
(
authEnabledProfile
.
excludedUrls
.
join
(
'
,
'
));
...
...
@@ -578,6 +580,7 @@ describe('OnDemandScansForm', () => {
expect
(
summary
).
toMatch
(
authEnabledProfile
.
auth
.
passwordField
);
expect
(
summary
).
toMatch
(
defaultPassword
);
expect
(
summary
).
toMatch
(
defaultRequestHeaders
);
expect
(
summary
).
toMatch
(
defaultSiteType
);
});
it
(
'
does not render the summary provided an invalid profile ID
'
,
async
()
=>
{
...
...
ee/spec/frontend/on_demand_scans/components/profile_selector/site_profile_selector_spec.js
View file @
7942afee
...
...
@@ -34,6 +34,7 @@ describe('OnDemandScansSiteProfileSelector', () => {
newSiteProfilePath
:
TEST_NEW_PATH
,
glFeatures
:
{
securityDastSiteProfilesAdditionalFields
:
true
,
securityDastSiteProfilesApiOption
:
true
,
},
},
slots
:
{
...
...
ee/spec/frontend/on_demand_scans/mocks/mock_data.js
View file @
7942afee
...
...
@@ -40,6 +40,7 @@ export const siteProfiles = [
id
:
'
gid://gitlab/DastSiteProfile/1
'
,
profileName
:
'
Site profile #1
'
,
targetUrl
:
'
https://foo.com
'
,
targetType
:
'
WEBSITE
'
,
normalizedTargetUrl
:
'
https://foo.com:443
'
,
editPath
:
'
/site_profiles/edit/1
'
,
validationStatus
:
'
PENDING_VALIDATION
'
,
...
...
@@ -59,6 +60,7 @@ export const siteProfiles = [
id
:
'
gid://gitlab/DastSiteProfile/2
'
,
profileName
:
'
Site profile #2
'
,
targetUrl
:
'
https://bar.com
'
,
targetType
:
'
API
'
,
normalizedTargetUrl
:
'
https://bar.com:443
'
,
editPath
:
'
/site_profiles/edit/2
'
,
validationStatus
:
'
PASSED_VALIDATION
'
,
...
...
@@ -87,4 +89,5 @@ export const policySiteProfile = {
},
excludedUrls
:
[
'
https://bar.com/logout
'
],
referencedInSecurityPolicies
:
[
'
some_policy
'
],
targetType
:
'
WEBSITE
'
,
};
ee/spec/frontend/security_configuration/dast_site_profiles_form/components/dast_site_profile_form_spec.js
View file @
7942afee
...
...
@@ -54,6 +54,7 @@ describe('DastSiteProfileForm', () => {
const
findExcludedUrlsInput
=
()
=>
wrapper
.
findByTestId
(
'
excluded-urls-input
'
);
const
findRequestHeadersInput
=
()
=>
wrapper
.
findByTestId
(
'
request-headers-input
'
);
const
findAuthCheckbox
=
()
=>
wrapper
.
findByTestId
(
'
auth-enable-checkbox
'
);
const
findTargetTypeOption
=
()
=>
wrapper
.
findByTestId
(
'
site-type-option
'
);
const
findSubmitButton
=
()
=>
wrapper
.
findByTestId
(
'
dast-site-profile-form-submit-button
'
);
const
findCancelButton
=
()
=>
wrapper
.
findByTestId
(
'
dast-site-profile-form-cancel-button
'
);
const
findAlert
=
()
=>
wrapper
.
findByTestId
(
'
dast-site-profile-form-alert
'
);
...
...
@@ -73,6 +74,28 @@ describe('DastSiteProfileForm', () => {
});
};
const
fillForm
=
async
()
=>
{
await
setFieldValue
(
findProfileNameInput
(),
profileName
);
await
setFieldValue
(
findTargetUrlInput
(),
targetUrl
);
await
setFieldValue
(
findExcludedUrlsInput
(),
excludedUrls
);
await
setFieldValue
(
findRequestHeadersInput
(),
requestHeaders
);
await
setAuthFieldsValues
(
siteProfileOne
.
auth
);
};
const
fillAndSubmitForm
=
async
()
=>
{
await
fillForm
();
submitForm
();
};
const
setTargetType
=
async
(
type
)
=>
{
const
radio
=
wrapper
.
findAll
(
'
input[type="radio"]
'
)
.
filter
((
r
)
=>
r
.
attributes
(
'
value
'
)
===
type
)
.
at
(
0
);
radio
.
element
.
selected
=
true
;
radio
.
trigger
(
'
change
'
);
};
const
mockClientFactory
=
(
handlers
)
=>
{
const
mockClient
=
createMockClient
();
...
...
@@ -110,6 +133,7 @@ describe('DastSiteProfileForm', () => {
provide
:
{
glFeatures
:
{
securityDastSiteProfilesAdditionalFields
:
true
,
securityDastSiteProfilesApiOption
:
true
,
},
},
},
...
...
@@ -175,10 +199,11 @@ describe('DastSiteProfileForm', () => {
createFullComponent
();
});
it
(
'
should render correctly
'
,
()
=>
{
it
(
'
should render correctly
with default values
'
,
()
=>
{
expect
(
findAuthSection
().
exists
()).
toBe
(
true
);
expect
(
findExcludedUrlsInput
().
exists
()).
toBe
(
true
);
expect
(
findRequestHeadersInput
().
exists
()).
toBe
(
true
);
expect
(
findTargetTypeOption
().
vm
.
$attrs
.
checked
).
toBe
(
'
WEBSITE
'
);
});
it
(
'
should have maxlength constraint
'
,
()
=>
{
...
...
@@ -216,6 +241,48 @@ describe('DastSiteProfileForm', () => {
expect
(
findByNameAttribute
(
'
password
'
).
element
.
value
).
toBe
(
''
);
});
});
describe
(
'
when target type is API
'
,
()
=>
{
beforeEach
(()
=>
{
setTargetType
(
'
API
'
);
});
it
(
'
should hide auth section
'
,
()
=>
{
expect
(
findAuthSection
().
exists
()).
toBe
(
false
);
});
describe
.
each
`
title | siteProfile | mutationVars | mutationKind
${
'
New site profile
'
}
|
${
null
}
|
${{}}
|
$
{
'
dastSiteProfileCreate
'
}
${
'
Edit site profile
'
}
|
${
siteProfileOne
}
|
${{
id
:
siteProfileOne
.
id
}
} |
${
'
dastSiteProfileUpdate
'
}
`
(
'
$title
'
,
({
siteProfile
,
mutationVars
,
mutationKind
})
=>
{
beforeEach
(()
=>
{
createFullComponent
({
propsData
:
{
siteProfile
,
},
});
});
it
(
'
form submission triggers correct GraphQL mutation
'
,
async
()
=>
{
await
fillForm
();
await
setTargetType
(
'
API
'
);
await
submitForm
();
expect
(
requestHandlers
[
mutationKind
]).
toHaveBeenCalledWith
({
input
:
{
profileName
,
targetUrl
,
fullPath
,
excludedUrls
:
siteProfileOne
.
excludedUrls
,
requestHeaders
,
targetType
:
'
API
'
,
...
mutationVars
,
},
});
});
});
});
});
describe
.
each
`
...
...
@@ -240,15 +307,6 @@ describe('DastSiteProfileForm', () => {
});
describe
(
'
submission
'
,
()
=>
{
const
fillAndSubmitForm
=
async
()
=>
{
await
setFieldValue
(
findProfileNameInput
(),
profileName
);
await
setFieldValue
(
findTargetUrlInput
(),
targetUrl
);
await
setFieldValue
(
findExcludedUrlsInput
(),
excludedUrls
);
await
setFieldValue
(
findRequestHeadersInput
(),
requestHeaders
);
await
setAuthFieldsValues
(
siteProfileOne
.
auth
);
submitForm
();
};
describe
(
'
on success
'
,
()
=>
{
beforeEach
(
async
()
=>
{
await
fillAndSubmitForm
();
...
...
@@ -267,6 +325,7 @@ describe('DastSiteProfileForm', () => {
fullPath
,
auth
:
siteProfileOne
.
auth
,
excludedUrls
:
siteProfileOne
.
excludedUrls
,
targetType
:
siteProfileOne
.
targetType
,
...
mutationVars
,
},
});
...
...
@@ -359,16 +418,17 @@ describe('DastSiteProfileForm', () => {
});
});
describe
(
'
when
feature flag is
off
'
,
()
=>
{
describe
(
'
when
all feature flags are
off
'
,
()
=>
{
const
mountOpts
=
{
provide
:
{
glFeatures
:
{
securityDastSiteProfilesAdditionalFields
:
false
,
securityDastSiteProfilesApiOption
:
false
,
},
},
};
const
fillAndSubmitForm
=
async
()
=>
{
const
fill
RequiredFields
AndSubmitForm
=
async
()
=>
{
await
setFieldValue
(
findProfileNameInput
(),
profileName
);
await
setFieldValue
(
findTargetUrlInput
(),
targetUrl
);
submitForm
();
...
...
@@ -380,6 +440,7 @@ describe('DastSiteProfileForm', () => {
expect
(
findAuthSection
().
exists
()).
toBe
(
false
);
expect
(
findExcludedUrlsInput
().
exists
()).
toBe
(
false
);
expect
(
findRequestHeadersInput
().
exists
()).
toBe
(
false
);
expect
(
findTargetTypeOption
().
exists
()).
toBe
(
false
);
});
describe
.
each
`
...
...
@@ -394,11 +455,11 @@ describe('DastSiteProfileForm', () => {
},
...
mountOpts
,
});
fillAndSubmitForm
();
fill
RequiredFields
AndSubmitForm
();
});
it
(
'
form submission triggers correct GraphQL mutation
'
,
async
()
=>
{
await
fillAndSubmitForm
();
await
fill
RequiredFields
AndSubmitForm
();
expect
(
requestHandlers
[
mutationKind
]).
toHaveBeenCalledWith
({
input
:
{
profileName
,
...
...
ee/spec/requests/projects/security/dast_site_profiles_controller_spec.rb
View file @
7942afee
...
...
@@ -108,6 +108,7 @@ RSpec.describe Projects::Security::DastSiteProfilesController, type: :request do
id:
global_id_of
(
dast_site_profile
),
name:
dast_site_profile
.
name
,
targetUrl:
dast_site_profile
.
dast_site
.
url
,
targetType:
dast_site_profile
.
target_type
.
upcase
,
excludedUrls:
dast_site_profile
.
excluded_urls
,
requestHeaders:
Dast
::
SiteProfilePresenter
::
REDACTED_REQUEST_HEADERS
,
auth:
{
...
...
locale/gitlab.pot
View file @
7942afee
...
...
@@ -10094,6 +10094,9 @@ msgstr ""
msgid "DastProfiles|Request headers"
msgstr ""
msgid "DastProfiles|Rest API"
msgstr ""
msgid "DastProfiles|Run scan"
msgstr ""
...
...
@@ -10139,6 +10142,9 @@ msgstr ""
msgid "DastProfiles|Site name"
msgstr ""
msgid "DastProfiles|Site type"
msgstr ""
msgid "DastProfiles|Spider timeout"
msgstr ""
...
...
@@ -10187,6 +10193,9 @@ msgstr ""
msgid "DastProfiles|Validation status"
msgstr ""
msgid "DastProfiles|Website"
msgstr ""
msgid "DastSiteValidation|Copy HTTP header to clipboard"
msgstr ""
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment