Commit 86ecf315 authored by Dheeraj Joshi's avatar Dheeraj Joshi Committed by Mark Florian

Add additional fields to DAST Site Profile Selector

  * Update profile selector summary
  * Create a new feature flag
  * Put the changes behind the FF
parent b7355aeb
---
name: security_dast_site_profiles_additional_fields
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/46848
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/292897
milestone: '13.7'
type: development
group: group::dynamic analysis
default_enabled: false
......@@ -24,6 +24,7 @@ import {
ERROR_MESSAGES,
SCANNER_PROFILES_QUERY,
SITE_PROFILES_QUERY,
SITE_PROFILES_EXTENDED_QUERY,
} from '../settings';
import dastOnDemandScanCreateMutation from '../graphql/dast_on_demand_scan_create.mutation.graphql';
import ProfileSelectorSummaryCell from './profile_selector/summary_cell.vue';
......@@ -74,11 +75,15 @@ export default {
'selectedScannerProfileId',
SCANNER_PROFILES_QUERY,
),
siteProfiles: createProfilesApolloOptions(
'siteProfiles',
'selectedSiteProfileId',
SITE_PROFILES_QUERY,
),
siteProfiles() {
return createProfilesApolloOptions(
'siteProfiles',
'selectedSiteProfileId',
this.glFeatures.securityDastSiteProfilesAdditionalFields
? SITE_PROFILES_EXTENDED_QUERY
: SITE_PROFILES_QUERY,
);
},
},
props: {
helpPagePath: {
......@@ -310,6 +315,42 @@ export default {
:value="selectedSiteProfile.targetUrl"
/>
</div>
<template v-if="glFeatures.securityDastSiteProfilesAdditionalFields">
<template v-if="selectedSiteProfile.auth.enabled">
<div class="row">
<profile-selector-summary-cell
:label="s__('DastProfiles|Authentication URL')"
:value="selectedSiteProfile.auth.url"
/>
</div>
<div class="row">
<profile-selector-summary-cell
:label="s__('DastProfiles|Username')"
:value="selectedSiteProfile.auth.username"
/>
</div>
<div class="row">
<profile-selector-summary-cell
:label="s__('DastProfiles|Username form field')"
:value="selectedSiteProfile.auth.usernameField"
/>
<profile-selector-summary-cell
:label="s__('DastProfiles|Password form field')"
:value="selectedSiteProfile.auth.passwordField"
/>
</div>
</template>
<div class="row">
<profile-selector-summary-cell
:label="s__('DastProfiles|Excluded URLs')"
:value="selectedSiteProfile.excludedUrls"
/>
<profile-selector-summary-cell
:label="s__('DastProfiles|Request headers')"
:value="selectedSiteProfile.requestHeaders"
/>
</div>
</template>
</template>
</site-profile-selector>
......
......@@ -17,8 +17,8 @@ export default {
<template>
<div class="col-md-6">
<div class="row gl-my-2">
<div class="col-md-3">{{ label }}:</div>
<div class="col-md-9">
<div class="col-md-4">{{ label }}:</div>
<div class="col-md-8">
<strong>{{ value }}</strong>
</div>
</div>
......
import dastScannerProfilesQuery from 'ee/security_configuration/dast_profiles/graphql/dast_scanner_profiles.query.graphql';
import dastSiteProfilesQuery from 'ee/security_configuration/dast_profiles/graphql/dast_site_profiles.query.graphql';
import dastSiteProfilesExtendedQuery from 'ee/security_configuration/dast_profiles/graphql/dast_site_profiles_extended.query.graphql';
import { s__ } from '~/locale';
export const ERROR_RUN_SCAN = 'ERROR_RUN_SCAN';
......@@ -27,3 +28,8 @@ export const SITE_PROFILES_QUERY = {
fetchQuery: dastSiteProfilesQuery,
fetchError: ERROR_FETCH_SITE_PROFILES,
};
export const SITE_PROFILES_EXTENDED_QUERY = {
...SITE_PROFILES_QUERY,
fetchQuery: dastSiteProfilesExtendedQuery,
};
#import "~/graphql_shared/fragments/pageInfo.fragment.graphql"
query DastSiteProfiles($fullPath: ID!, $after: String, $before: String, $first: Int, $last: Int) {
project(fullPath: $fullPath) {
siteProfiles: dastSiteProfiles(after: $after, before: $before, first: $first, last: $last)
@connection(key: "dastSiteProfiles") {
pageInfo {
...PageInfo
}
edges {
cursor
node {
id
profileName
normalizedTargetUrl
targetUrl
editPath
validationStatus
auth {
enabled
url
usernameField
passwordField
username
}
excludedUrls
requestHeaders
}
}
}
}
}
......@@ -5,6 +5,7 @@ module Projects
before_action do
authorize_read_on_demand_scans!
push_frontend_feature_flag(:security_on_demand_scans_site_validation, @project)
push_frontend_feature_flag(:security_dast_site_profiles_additional_fields, @project, default_enabled: :yaml)
end
feature_category :dynamic_application_security_testing
......
......@@ -337,4 +337,39 @@ describe('OnDemandScansForm', () => {
expect(subject.find(selector).attributes('value')).toBe(profile.id);
});
});
describe('site profile summary', () => {
const [authEnabledProfile] = siteProfiles;
const selectSiteProfile = profile => {
subject.find(SiteProfileSelector).vm.$emit('input', profile.id);
return subject.vm.$nextTick();
};
beforeEach(() => {
mountSubject({
provide: {
glFeatures: {
securityDastSiteProfilesAdditionalFields: true,
},
},
data: {
siteProfiles,
},
});
});
it('renders all fields correctly', async () => {
await selectSiteProfile(authEnabledProfile);
const summary = subject.find(SiteProfileSelector).text();
expect(summary).toMatch(authEnabledProfile.targetUrl);
expect(summary).toMatch(authEnabledProfile.excludedUrls);
expect(summary).toMatch(authEnabledProfile.requestHeaders);
expect(summary).toMatch(authEnabledProfile.auth.url);
expect(summary).toMatch(authEnabledProfile.auth.username);
expect(summary).toMatch(authEnabledProfile.auth.usernameField);
expect(summary).toMatch(authEnabledProfile.auth.passwordField);
});
});
});
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`OnDemandScansProfileSummaryCell renders properly 1`] = `
"<div class=\\"col-md-6\\">
<div class=\\"row gl-my-2\\">
<div class=\\"col-md-3\\">Row Label:</div>
<div class=\\"col-md-9\\"><strong>Row Value</strong></div>
<div
class="col-md-6"
>
<div
class="row gl-my-2"
>
<div
class="col-md-4"
>
Row Label:
</div>
<div
class="col-md-8"
>
<strong>
Row Value
</strong>
</div>
</div>
</div>"
</div>
`;
......@@ -32,7 +32,10 @@ describe('OnDemandScansSiteProfileSelector', () => {
provide: {
siteProfilesLibraryPath: TEST_LIBRARY_PATH,
newSiteProfilePath: TEST_NEW_PATH,
glFeatures: { securityOnDemandScansSiteValidation: true },
glFeatures: {
securityOnDemandScansSiteValidation: true,
securityDastSiteProfilesAdditionalFields: true,
},
},
slots: {
summary: `<div>${profiles[0].profileName}'s summary</div>`,
......@@ -93,12 +96,15 @@ describe('OnDemandScansSiteProfileSelector', () => {
expect(sel.attributes()).toMatchObject(TEST_ATTRS);
});
describe('feature flag disabled', () => {
describe('feature flags disabled', () => {
beforeEach(() => {
createComponent({
propsData: { profiles },
provide: {
glFeatures: { securityOnDemandScansSiteValidation: false },
glFeatures: {
securityOnDemandScansSiteValidation: false,
securityDastSiteProfilesAdditionalFields: false,
},
},
});
});
......
......@@ -20,6 +20,6 @@ describe('OnDemandScansProfileSummaryCell', () => {
it('renders properly', () => {
createFullComponent();
expect(wrapper.html()).toMatchSnapshot();
expect(wrapper.element).toMatchSnapshot();
});
});
......@@ -29,6 +29,15 @@ export const siteProfiles = [
normalizedTargetUrl: 'https://foo.com:443',
editPath: '/site_profiles/edit/1',
validationStatus: 'PENDING_VALIDATION',
auth: {
enabled: true,
url: 'https://foo.com/login',
usernameField: 'username',
passwordField: 'password',
username: 'admin',
},
excludedUrls: 'https://foo.com/logout,https://foo.com/send_mail',
requestHeaders: 'log-identifier: dast-active-scan',
},
{
id: 'gid://gitlab/DastSiteProfile/2',
......@@ -37,5 +46,10 @@ export const siteProfiles = [
normalizedTargetUrl: 'https://bar.com:443',
editPath: '/site_profiles/edit/2',
validationStatus: 'PASSED_VALIDATION',
auth: {
enabled: false,
},
excludedUrls: 'https://bar.com/logout',
requestHeaders: 'auth: gitlab-dast',
},
];
......@@ -8683,6 +8683,9 @@ msgstr ""
msgid "DastProfiles|Error Details"
msgstr ""
msgid "DastProfiles|Excluded URLs"
msgstr ""
msgid "DastProfiles|Hide debug messages"
msgstr ""
......@@ -8731,6 +8734,9 @@ msgstr ""
msgid "DastProfiles|Profile name"
msgstr ""
msgid "DastProfiles|Request headers"
msgstr ""
msgid "DastProfiles|Run the AJAX spider, in addition to the traditional spider, to crawl the target site."
msgstr ""
......
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