Commit 978048b8 authored by Mikołaj Wawrzyniak's avatar Mikołaj Wawrzyniak

Merge branch '295246-saved-scans-tab' into 'master'

Add DAST Saved Scans tab

See merge request gitlab-org/gitlab!51247
parents 7f1848ac 5d7a9bc4
...@@ -2,10 +2,11 @@ ...@@ -2,10 +2,11 @@
import { GlDropdown, GlDropdownItem, GlTab, GlTabs } from '@gitlab/ui'; import { GlDropdown, GlDropdownItem, GlTab, GlTabs } from '@gitlab/ui';
import { camelCase, kebabCase } from 'lodash'; import { camelCase, kebabCase } from 'lodash';
import * as Sentry from '~/sentry/wrapper'; import * as Sentry from '~/sentry/wrapper';
import { s__ } from '~/locale'; import { __, s__ } from '~/locale';
import { getLocationHash } from '~/lib/utils/url_utility'; import { getLocationHash } from '~/lib/utils/url_utility';
import * as cacheUtils from '../graphql/cache_utils'; import * as cacheUtils from '../graphql/cache_utils';
import { getProfileSettings } from '../settings/profiles'; import { getProfileSettings } from '../settings/profiles';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
export default { export default {
components: { components: {
...@@ -14,6 +15,7 @@ export default { ...@@ -14,6 +15,7 @@ export default {
GlTab, GlTab,
GlTabs, GlTabs,
}, },
mixins: [glFeatureFlagsMixin()],
props: { props: {
createNewProfilePaths: { createNewProfilePaths: {
type: Object, type: Object,
...@@ -37,6 +39,7 @@ export default { ...@@ -37,6 +39,7 @@ export default {
return getProfileSettings({ return getProfileSettings({
createNewProfilePaths, createNewProfilePaths,
isDastSavedScansEnabled: this.glFeatures.dastSavedScans,
}); });
}, },
tabIndex: { tabIndex: {
...@@ -210,8 +213,8 @@ export default { ...@@ -210,8 +213,8 @@ export default {
}, },
profilesPerPage: 10, profilesPerPage: 10,
i18n: { i18n: {
heading: s__('DastProfiles|Manage Profiles'), heading: s__('DastProfiles|Manage DAST scans'),
newProfileDropdownLabel: s__('DastProfiles|New Profile'), newProfileDropdownLabel: __('New'),
subHeading: s__( subHeading: s__(
'DastProfiles|Save commonly used configurations for target sites and scan specifications as profiles. Use these with an on-demand scan.', 'DastProfiles|Save commonly used configurations for target sites and scan specifications as profiles. Use these with an on-demand scan.',
), ),
......
<script>
import ProfilesList from './dast_profiles_list.vue';
import ScanTypeBadge from './dast_scan_type_badge.vue';
export default {
components: {
ProfilesList,
ScanTypeBadge,
},
};
</script>
<template>
<profiles-list v-bind="$attrs" v-on="$listeners">
<!-- eslint-disable-next-line vue/valid-v-slot -->
<template #cell(dastScannerProfile.scanType)="{ value }">
<scan-type-badge :scan-type="value" />
</template>
</profiles-list>
</template>
<script>
import { GlBadge } from '@gitlab/ui';
import {
SCAN_TYPE,
SCAN_TYPE_LABEL,
} from 'ee/security_configuration/dast_scanner_profiles/constants';
const scanTypeToBadgeVariantMap = {
[SCAN_TYPE.ACTIVE]: 'warning',
[SCAN_TYPE.PASSIVE]: 'neutral',
};
export default {
name: 'DastScanTypeBadge',
components: {
GlBadge,
},
props: {
scanType: {
type: String,
required: true,
validator: (value) => Boolean(SCAN_TYPE[value]),
},
},
computed: {
variant() {
return scanTypeToBadgeVariantMap[this.scanType];
},
label() {
return SCAN_TYPE_LABEL[this.scanType].toLowerCase();
},
},
};
</script>
<template>
<gl-badge size="sm" :variant="variant">
{{ label }}
</gl-badge>
</template>
...@@ -10,11 +10,17 @@ export default () => { ...@@ -10,11 +10,17 @@ export default () => {
} }
const { const {
dataset: { newDastScannerProfilePath, newDastSiteProfilePath, projectFullPath }, dataset: {
newDastSavedScanPath,
newDastScannerProfilePath,
newDastSiteProfilePath,
projectFullPath,
},
} = el; } = el;
const props = { const props = {
createNewProfilePaths: { createNewProfilePaths: {
savedScan: newDastSavedScanPath,
scannerProfile: newDastScannerProfilePath, scannerProfile: newDastScannerProfilePath,
siteProfile: newDastSiteProfilePath, siteProfile: newDastSiteProfilePath,
}, },
......
#import "~/graphql_shared/fragments/pageInfo.fragment.graphql"
query DastSavedScans($fullPath: ID!, $after: String, $before: String, $first: Int, $last: Int) {
project @client {
savedScans(after: $after, before: $before, first: $first, last: $last) {
pageInfo {
...PageInfo
}
edges {
node {
id
name
dastSiteProfile {
id
targetUrl
}
dastScannerProfile {
id
scanType
}
editPath
}
}
}
}
}
mutation dastSavedScansDelete($input: DastSavedScansDeleteInput!) {
savedScansDelete(input: $input) @client {
errors
}
}
/* eslint-disable @gitlab/require-i18n-strings */
import Vue from 'vue'; import Vue from 'vue';
import VueApollo from 'vue-apollo'; import VueApollo from 'vue-apollo';
import { range } from 'lodash';
import createDefaultClient from '~/lib/graphql'; import createDefaultClient from '~/lib/graphql';
Vue.use(VueApollo); Vue.use(VueApollo);
export default new VueApollo({ // NOTE: We currently mock some fake DAST scans while the feature is feature-flagged and the
defaultClient: createDefaultClient( // backend is being worked on.
{}, // This will be cleaned up as part of https://gitlab.com/gitlab-org/gitlab/-/issues/295248.
{ let id = 0;
assumeImmutableResults: true, const generateFakeDastScan = () => {
id += 1;
return {
node: {
id,
name: `My daily scan #${id}`,
description: 'Tests for SQL injection',
dastSiteProfile: {
id,
targetUrl: 'http://example.com ',
__typename: 'DastSiteProfile',
},
dastScannerProfile: {
id,
scanType: Math.random() < 0.5 ? 'PASSIVE' : 'ACTIVE',
__typename: 'DastScannerProfile',
},
editPath: '/on_demand_scans/1/edit',
__typename: 'DastSavedScan',
}, },
), __typename: 'DastSavedScanEdge',
};
};
const resolvers = {
Query: {
project: () => ({
__typename: 'Project',
savedScans: {
pageInfo: {
hasNextPage: true,
hasPreviousPage: false,
startCursor: 'startCursor',
endCursor: 'endCursor',
__typename: 'PageInfo',
},
edges: range(10).map(generateFakeDastScan),
__typename: 'DastSavedScanConnection',
},
}),
},
};
export default new VueApollo({
defaultClient: createDefaultClient(resolvers, {
assumeImmutableResults: true,
}),
}); });
import dastSavedScansQuery from 'ee/security_configuration/dast_profiles/graphql/dast_saved_scans.query.graphql';
import dastSavedScansDelete from 'ee/security_configuration/dast_profiles/graphql/dast_saved_scans_delete.mutation.graphql';
import dastSiteProfilesQuery from 'ee/security_configuration/dast_profiles/graphql/dast_site_profiles.query.graphql'; import dastSiteProfilesQuery from 'ee/security_configuration/dast_profiles/graphql/dast_site_profiles.query.graphql';
import dastSiteProfilesDelete from 'ee/security_configuration/dast_profiles/graphql/dast_site_profiles_delete.mutation.graphql'; import dastSiteProfilesDelete from 'ee/security_configuration/dast_profiles/graphql/dast_site_profiles_delete.mutation.graphql';
import dastScannerProfilesQuery from 'ee/security_configuration/dast_profiles/graphql/dast_scanner_profiles.query.graphql'; import dastScannerProfilesQuery from 'ee/security_configuration/dast_profiles/graphql/dast_scanner_profiles.query.graphql';
import dastScannerProfilesDelete from 'ee/security_configuration/dast_profiles/graphql/dast_scanner_profiles_delete.mutation.graphql'; import dastScannerProfilesDelete from 'ee/security_configuration/dast_profiles/graphql/dast_scanner_profiles_delete.mutation.graphql';
import { dastProfilesDeleteResponse } from 'ee/security_configuration/dast_profiles/graphql/cache_utils'; import { dastProfilesDeleteResponse } from 'ee/security_configuration/dast_profiles/graphql/cache_utils';
import DastSavedScansList from 'ee/security_configuration/dast_profiles/components/dast_saved_scans_list.vue';
import DastSiteProfileList from 'ee/security_configuration/dast_profiles/components/dast_site_profiles_list.vue'; import DastSiteProfileList from 'ee/security_configuration/dast_profiles/components/dast_site_profiles_list.vue';
import DastScannerProfileList from 'ee/security_configuration/dast_profiles/components/dast_scanner_profiles_list.vue'; import DastScannerProfileList from 'ee/security_configuration/dast_profiles/components/dast_scanner_profiles_list.vue';
import { s__ } from '~/locale'; import { s__ } from '~/locale';
export const getProfileSettings = ({ createNewProfilePaths }) => ({ export const getProfileSettings = ({ createNewProfilePaths, isDastSavedScansEnabled }) => ({
...(isDastSavedScansEnabled
? {
savedScans: {
profileType: 'savedScans',
createNewProfilePath: createNewProfilePaths.savedScan,
graphQL: {
query: dastSavedScansQuery,
deletion: {
mutation: dastSavedScansDelete,
optimisticResponse: dastProfilesDeleteResponse({
mutationName: 'savedScanDelete',
payloadTypeName: 'DastSavedScanDeletePayload',
}),
},
},
component: DastSavedScansList,
tableFields: [
{
label: s__('DastProfiles|Scan'),
key: 'name',
},
{
label: s__('DastProfiles|Target'),
key: 'dastSiteProfile.targetUrl',
},
{
label: s__('DastProfiles|Scan mode'),
key: 'dastScannerProfile.scanType',
},
],
i18n: {
createNewLinkText: s__('DastProfiles|DAST Scan'),
name: s__('DastProfiles|Saved Scans'),
errorMessages: {
fetchNetworkError: s__(
'DastProfiles|Could not fetch saved scans. Please refresh the page, or try again later.',
),
deletionNetworkError: s__(
'DastProfiles|Could not delete saved scan. Please refresh the page, or try again later.',
),
deletionBackendError: s__('DastProfiles|Could not delete saved scans:'),
},
},
},
}
: {}),
siteProfiles: { siteProfiles: {
profileType: 'siteProfiles', profileType: 'siteProfiles',
createNewProfilePath: createNewProfilePaths.siteProfile, createNewProfilePath: createNewProfilePaths.siteProfile,
......
...@@ -6,6 +6,7 @@ module Projects ...@@ -6,6 +6,7 @@ module Projects
before_action do before_action do
authorize_read_on_demand_scans! authorize_read_on_demand_scans!
push_frontend_feature_flag(:security_on_demand_scans_site_validation, @project, default_enabled: :yaml) push_frontend_feature_flag(:security_on_demand_scans_site_validation, @project, default_enabled: :yaml)
push_frontend_feature_flag(:dast_saved_scans, @project, default_enabled: :yaml)
end end
feature_category :dynamic_application_security_testing feature_category :dynamic_application_security_testing
......
- add_to_breadcrumbs _('Security Configuration'), project_security_configuration_path(@project) - add_to_breadcrumbs _('Security Configuration'), project_security_configuration_path(@project)
- breadcrumb_title s_('DastProfiles|Manage profiles') - breadcrumb_title s_('DastProfiles|Manage DAST scans')
- page_title s_('DastProfiles|Manage profiles') - page_title s_('DastProfiles|Manage DAST scans')
.js-dast-profiles{ data: { new_dast_site_profile_path: new_project_security_configuration_dast_profiles_dast_site_profile_path(@project), .js-dast-profiles{ data: { new_dast_saved_scan_path: new_project_on_demand_scan_path(@project),
new_dast_site_profile_path: new_project_security_configuration_dast_profiles_dast_site_profile_path(@project),
new_dast_scanner_profile_path: new_project_security_configuration_dast_profiles_dast_scanner_profile_path(@project), new_dast_scanner_profile_path: new_project_security_configuration_dast_profiles_dast_scanner_profile_path(@project),
project_full_path: @project.path_with_namespace } } project_full_path: @project.path_with_namespace } }
...@@ -5,6 +5,7 @@ import { merge } from 'lodash'; ...@@ -5,6 +5,7 @@ import { merge } from 'lodash';
import DastProfiles from 'ee/security_configuration/dast_profiles/components/dast_profiles.vue'; import DastProfiles from 'ee/security_configuration/dast_profiles/components/dast_profiles.vue';
import setWindowLocation from 'helpers/set_window_location_helper'; import setWindowLocation from 'helpers/set_window_location_helper';
const TEST_NEW_DAST_SAVED_SCAN_PATH = '/-/on_demand_scans/new';
const TEST_NEW_DAST_SCANNER_PROFILE_PATH = '/-/on_demand_scans/scanner_profiles/new'; const TEST_NEW_DAST_SCANNER_PROFILE_PATH = '/-/on_demand_scans/scanner_profiles/new';
const TEST_NEW_DAST_SITE_PROFILE_PATH = '/-/on_demand_scans/site_profiles/new'; const TEST_NEW_DAST_SITE_PROFILE_PATH = '/-/on_demand_scans/site_profiles/new';
const TEST_PROJECT_FULL_PATH = '/namespace/project'; const TEST_PROJECT_FULL_PATH = '/namespace/project';
...@@ -15,6 +16,7 @@ describe('EE - DastProfiles', () => { ...@@ -15,6 +16,7 @@ describe('EE - DastProfiles', () => {
const createComponentFactory = (mountFn = shallowMount) => (options = {}) => { const createComponentFactory = (mountFn = shallowMount) => (options = {}) => {
const defaultProps = { const defaultProps = {
createNewProfilePaths: { createNewProfilePaths: {
savedScan: TEST_NEW_DAST_SAVED_SCAN_PATH,
scannerProfile: TEST_NEW_DAST_SCANNER_PROFILE_PATH, scannerProfile: TEST_NEW_DAST_SCANNER_PROFILE_PATH,
siteProfile: TEST_NEW_DAST_SITE_PROFILE_PATH, siteProfile: TEST_NEW_DAST_SITE_PROFILE_PATH,
}, },
...@@ -24,6 +26,9 @@ describe('EE - DastProfiles', () => { ...@@ -24,6 +26,9 @@ describe('EE - DastProfiles', () => {
const defaultMocks = { const defaultMocks = {
$apollo: { $apollo: {
queries: { queries: {
savedScans: {
fetchMore: jest.fn().mockResolvedValue(),
},
siteProfiles: { siteProfiles: {
fetchMore: jest.fn().mockResolvedValue(), fetchMore: jest.fn().mockResolvedValue(),
}, },
...@@ -43,6 +48,11 @@ describe('EE - DastProfiles', () => { ...@@ -43,6 +48,11 @@ describe('EE - DastProfiles', () => {
{ {
propsData: defaultProps, propsData: defaultProps,
mocks: defaultMocks, mocks: defaultMocks,
provide: {
glFeatures: {
dastSavedScans: true,
},
},
}, },
options, options,
), ),
...@@ -72,31 +82,26 @@ describe('EE - DastProfiles', () => { ...@@ -72,31 +82,26 @@ describe('EE - DastProfiles', () => {
it('shows a heading that describes the purpose of the page', () => { it('shows a heading that describes the purpose of the page', () => {
createFullComponent(); createFullComponent();
const heading = withinComponent().getByRole('heading', { name: /manage profiles/i }); const heading = withinComponent().getByRole('heading', { name: /manage dast scans/i });
expect(heading).not.toBe(null); expect(heading).not.toBe(null);
}); });
it('has a "New Profile" dropdown menu', () => { it('has a "New" dropdown menu', () => {
createComponent(); createComponent();
expect(getDropdownComponent().props('text')).toBe('New Profile'); expect(getDropdownComponent().props('text')).toBe('New');
}); });
it(`shows a "Site Profile" dropdown item that links to ${TEST_NEW_DAST_SITE_PROFILE_PATH}`, () => { it.each`
createComponent(); itemName | href
${'DAST Scan'} | ${TEST_NEW_DAST_SAVED_SCAN_PATH}
expect(getSiteProfilesDropdownItem('Site Profile').getAttribute('href')).toBe( ${'Site Profile'} | ${TEST_NEW_DAST_SITE_PROFILE_PATH}
TEST_NEW_DAST_SITE_PROFILE_PATH, ${'Scanner Profile'} | ${TEST_NEW_DAST_SCANNER_PROFILE_PATH}
); `('shows a "$itemName" dropdown item that links to $href', ({ itemName, href }) => {
});
it(`shows a "Scanner Profile" dropdown item that links to ${TEST_NEW_DAST_SCANNER_PROFILE_PATH}`, () => {
createComponent(); createComponent();
expect(getSiteProfilesDropdownItem('Scanner Profile').getAttribute('href')).toBe( expect(getSiteProfilesDropdownItem(itemName).getAttribute('href')).toBe(href);
TEST_NEW_DAST_SCANNER_PROFILE_PATH,
);
}); });
}); });
...@@ -116,7 +121,8 @@ describe('EE - DastProfiles', () => { ...@@ -116,7 +121,8 @@ describe('EE - DastProfiles', () => {
it.each` it.each`
tabName | shouldBeSelectedByDefault tabName | shouldBeSelectedByDefault
${'Site Profiles'} | ${true} ${'Saved Scans'} | ${true}
${'Site Profiles'} | ${false}
${'Scanner Profiles'} | ${false} ${'Scanner Profiles'} | ${false}
`( `(
'shows a "$tabName" tab which has "selected" set to "$shouldBeSelectedByDefault"', 'shows a "$tabName" tab which has "selected" set to "$shouldBeSelectedByDefault"',
...@@ -133,8 +139,9 @@ describe('EE - DastProfiles', () => { ...@@ -133,8 +139,9 @@ describe('EE - DastProfiles', () => {
describe.each` describe.each`
tabName | index | givenLocationHash tabName | index | givenLocationHash
${'Site Profiles'} | ${0} | ${'site-profiles'} ${'Saved Scans'} | ${0} | ${'saved-scans'}
${'Scanner Profiles'} | ${1} | ${'scanner-profiles'} ${'Site Profiles'} | ${1} | ${'site-profiles'}
${'Scanner Profiles'} | ${2} | ${'scanner-profiles'}
`('with location hash set to "$givenLocationHash"', ({ tabName, index, givenLocationHash }) => { `('with location hash set to "$givenLocationHash"', ({ tabName, index, givenLocationHash }) => {
beforeEach(() => { beforeEach(() => {
setWindowLocation(`http://foo.com/index#${givenLocationHash}`); setWindowLocation(`http://foo.com/index#${givenLocationHash}`);
...@@ -166,6 +173,7 @@ describe('EE - DastProfiles', () => { ...@@ -166,6 +173,7 @@ describe('EE - DastProfiles', () => {
describe.each` describe.each`
description | profileType description | profileType
${'Saved Scans List'} | ${'savedScans'}
${'Site Profiles List'} | ${'siteProfiles'} ${'Site Profiles List'} | ${'siteProfiles'}
${'Scanner Profiles List'} | ${'scannerProfiles'} ${'Scanner Profiles List'} | ${'scannerProfiles'}
`('$description', ({ profileType }) => { `('$description', ({ profileType }) => {
...@@ -220,4 +228,33 @@ describe('EE - DastProfiles', () => { ...@@ -220,4 +228,33 @@ describe('EE - DastProfiles', () => {
expect(mutate).toHaveBeenCalledTimes(1); expect(mutate).toHaveBeenCalledTimes(1);
}); });
}); });
describe('dastSavedScans feature flag disabled', () => {
beforeEach(() => {
createFullComponent({
provide: {
glFeatures: {
dastSavedScans: false,
},
},
});
});
it('does not show a "DAST Scan" item in the dropdown', () => {
expect(getSiteProfilesDropdownItem('DAST Scan')).toBe(null);
});
it('shows only 2 tabs', () => {
expect(withinComponent().getAllByRole('tab')).toHaveLength(2);
});
it('"Site Profile" tab should be selected by default', () => {
const tab = getTab({
tabName: 'Site Profiles',
selected: true,
});
expect(tab).not.toBe(null);
});
});
}); });
import { mount, shallowMount } from '@vue/test-utils';
import { merge } from 'lodash';
import Component from 'ee/security_configuration/dast_profiles/components/dast_saved_scans_list.vue';
import ProfilesList from 'ee/security_configuration/dast_profiles/components/dast_profiles_list.vue';
import { savedScans } from '../mocks/mock_data';
describe('EE - DastSavedScansList', () => {
let wrapper;
const defaultProps = {
profiles: [],
tableLabel: 'Saved scans',
fields: [
{ key: 'name' },
{ key: 'dastSiteProfile.targetUrl' },
{ key: 'dastScannerProfile.scanType' },
],
profilesPerPage: 10,
errorMessage: '',
errorDetails: [],
fullPath: '/namespace/project',
hasMoreProfilesToLoad: false,
isLoading: false,
};
const wrapperFactory = (mountFn = shallowMount) => (options = {}) => {
wrapper = mountFn(
Component,
merge(
{
propsData: defaultProps,
},
options,
),
);
};
const createFullComponent = wrapperFactory(mount);
const findProfileList = () => wrapper.find(ProfilesList);
afterEach(() => {
wrapper.destroy();
});
it('renders profile list properly', () => {
createFullComponent({
propsData: { profiles: savedScans },
});
expect(findProfileList()).toExist();
});
it('passes down the props properly', () => {
createFullComponent();
expect(findProfileList().props()).toEqual(defaultProps);
});
it('sets listeners on profile list component', () => {
const inputHandler = jest.fn();
createFullComponent({
listeners: {
input: inputHandler,
},
});
findProfileList().vm.$emit('input');
expect(inputHandler).toHaveBeenCalled();
});
});
import { shallowMount } from '@vue/test-utils';
import { GlBadge } from '@gitlab/ui';
import { SCAN_TYPE } from 'ee/security_configuration/dast_scanner_profiles/constants';
import DastScanTypeBadge from 'ee/security_configuration/dast_profiles/components/dast_scan_type_badge.vue';
describe('EE - DastScanTypeBadge', () => {
let wrapper;
const findBadge = () => wrapper.find(GlBadge);
const wrapperFactory = (mountFn = shallowMount) => (options = {}) => {
wrapper = mountFn(DastScanTypeBadge, options);
};
const createComponent = wrapperFactory();
afterEach(() => {
wrapper.destroy();
});
it.each`
scanType | variant
${SCAN_TYPE.ACTIVE} | ${'warning'}
${SCAN_TYPE.PASSIVE} | ${'neutral'}
`('renders a $variant badge for $scanType scans', ({ scanType, variant }) => {
createComponent({
propsData: {
scanType,
},
});
expect(findBadge().props('variant')).toBe(variant);
});
});
...@@ -61,3 +61,13 @@ export const scannerProfiles = [ ...@@ -61,3 +61,13 @@ export const scannerProfiles = [
showDebugMessages: true, showDebugMessages: true,
}, },
]; ];
export const savedScans = [
{
id: 'gid://gitlab/DastScan/1',
name: 'Scan 1',
dastSiteProfile: siteProfiles[0],
dastScannerProfile: scannerProfiles[0],
editPath: '/1/edit',
},
];
...@@ -12,6 +12,10 @@ RSpec.describe "projects/security/dast_profiles/show", type: :view do ...@@ -12,6 +12,10 @@ RSpec.describe "projects/security/dast_profiles/show", type: :view do
expect(rendered).to have_selector('.js-dast-profiles') expect(rendered).to have_selector('.js-dast-profiles')
end end
it 'passes new dast saved scan path' do
expect(rendered).to include '/on_demand_scans/new'
end
it 'passes new dast site profile path' do it 'passes new dast site profile path' do
expect(rendered).to include '/security/configuration/dast_profiles/dast_site_profiles/new' expect(rendered).to include '/security/configuration/dast_profiles/dast_site_profiles/new'
end end
......
...@@ -8800,6 +8800,12 @@ msgstr "" ...@@ -8800,6 +8800,12 @@ msgstr ""
msgid "DastProfiles|Could not create the site profile. Please try again." msgid "DastProfiles|Could not create the site profile. Please try again."
msgstr "" msgstr ""
msgid "DastProfiles|Could not delete saved scan. Please refresh the page, or try again later."
msgstr ""
msgid "DastProfiles|Could not delete saved scans:"
msgstr ""
msgid "DastProfiles|Could not delete scanner profile. Please refresh the page, or try again later." msgid "DastProfiles|Could not delete scanner profile. Please refresh the page, or try again later."
msgstr "" msgstr ""
...@@ -8812,6 +8818,9 @@ msgstr "" ...@@ -8812,6 +8818,9 @@ msgstr ""
msgid "DastProfiles|Could not delete site profiles:" msgid "DastProfiles|Could not delete site profiles:"
msgstr "" msgstr ""
msgid "DastProfiles|Could not fetch saved scans. Please refresh the page, or try again later."
msgstr ""
msgid "DastProfiles|Could not fetch scanner profiles. Please refresh the page, or try again later." msgid "DastProfiles|Could not fetch scanner profiles. Please refresh the page, or try again later."
msgstr "" msgstr ""
...@@ -8824,6 +8833,9 @@ msgstr "" ...@@ -8824,6 +8833,9 @@ msgstr ""
msgid "DastProfiles|Could not update the site profile. Please try again." msgid "DastProfiles|Could not update the site profile. Please try again."
msgstr "" msgstr ""
msgid "DastProfiles|DAST Scan"
msgstr ""
msgid "DastProfiles|Debug messages" msgid "DastProfiles|Debug messages"
msgstr "" msgstr ""
...@@ -8866,7 +8878,7 @@ msgstr "" ...@@ -8866,7 +8878,7 @@ msgstr ""
msgid "DastProfiles|Include debug messages in the DAST console output." msgid "DastProfiles|Include debug messages in the DAST console output."
msgstr "" msgstr ""
msgid "DastProfiles|Manage Profiles" msgid "DastProfiles|Manage DAST scans"
msgstr "" msgstr ""
msgid "DastProfiles|Manage profiles" msgid "DastProfiles|Manage profiles"
...@@ -8878,9 +8890,6 @@ msgstr "" ...@@ -8878,9 +8890,6 @@ msgstr ""
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds" msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr "" msgstr ""
msgid "DastProfiles|New Profile"
msgstr ""
msgid "DastProfiles|New scanner profile" msgid "DastProfiles|New scanner profile"
msgstr "" msgstr ""
...@@ -8920,6 +8929,12 @@ msgstr "" ...@@ -8920,6 +8929,12 @@ msgstr ""
msgid "DastProfiles|Save profile" msgid "DastProfiles|Save profile"
msgstr "" msgstr ""
msgid "DastProfiles|Saved Scans"
msgstr ""
msgid "DastProfiles|Scan"
msgstr ""
msgid "DastProfiles|Scan mode" msgid "DastProfiles|Scan mode"
msgstr "" msgstr ""
...@@ -8947,6 +8962,9 @@ msgstr "" ...@@ -8947,6 +8962,9 @@ msgstr ""
msgid "DastProfiles|Spider timeout" msgid "DastProfiles|Spider timeout"
msgstr "" msgstr ""
msgid "DastProfiles|Target"
msgstr ""
msgid "DastProfiles|Target URL" msgid "DastProfiles|Target URL"
msgstr "" 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