diff options
Diffstat (limited to 'app/assets/javascripts/security_configuration')
6 files changed, 166 insertions, 34 deletions
diff --git a/app/assets/javascripts/security_configuration/components/app.vue b/app/assets/javascripts/security_configuration/components/app.vue index bc13150c99c..75d2b324623 100644 --- a/app/assets/javascripts/security_configuration/components/app.vue +++ b/app/assets/javascripts/security_configuration/components/app.vue @@ -1,12 +1,14 @@ <script> import { GlTab, GlTabs, GlSprintf, GlLink, GlAlert } from '@gitlab/ui'; import { __, s__ } from '~/locale'; +import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue'; import UserCalloutDismisser from '~/vue_shared/components/user_callout_dismisser.vue'; import AutoDevOpsAlert from './auto_dev_ops_alert.vue'; import AutoDevOpsEnabledAlert from './auto_dev_ops_enabled_alert.vue'; import { AUTO_DEVOPS_ENABLED_ALERT_DISMISSED_STORAGE_KEY } from './constants'; import FeatureCard from './feature_card.vue'; +import TrainingProviderList from './training_provider_list.vue'; import SectionLayout from './section_layout.vue'; import UpgradeBanner from './upgrade_banner.vue'; @@ -23,6 +25,8 @@ export const i18n = { any subsequent feature branch you create will include the scan.`, ), securityConfiguration: __('Security Configuration'), + vulnerabilityManagement: s__('SecurityConfiguration|Vulnerability Management'), + securityTraining: s__('SecurityConfiguration|Security training'), }; export default { @@ -40,7 +44,9 @@ export default { SectionLayout, UpgradeBanner, UserCalloutDismisser, + TrainingProviderList, }, + mixins: [glFeatureFlagsMixin()], inject: ['projectPath'], props: { augmentedSecurityFeatures: { @@ -231,6 +237,17 @@ export default { </template> </section-layout> </gl-tab> + <gl-tab + v-if="glFeatures.secureVulnerabilityTraining" + data-testid="vulnerability-management-tab" + :title="$options.i18n.vulnerabilityManagement" + > + <section-layout :heading="$options.i18n.securityTraining"> + <template #features> + <training-provider-list /> + </template> + </section-layout> + </gl-tab> </gl-tabs> </article> </template> diff --git a/app/assets/javascripts/security_configuration/components/constants.js b/app/assets/javascripts/security_configuration/components/constants.js index 9c80506549e..dd8ba72ad1f 100644 --- a/app/assets/javascripts/security_configuration/components/constants.js +++ b/app/assets/javascripts/security_configuration/components/constants.js @@ -22,6 +22,7 @@ import configureSecretDetectionMutation from '../graphql/configure_secret_detect /** * Translations & helpPagePaths for Security Configuration Page + * Make sure to add new scanner translations to the SCANNER_NAMES_MAP below. */ export const SAST_NAME = __('Static Application Security Testing (SAST)'); @@ -138,6 +139,18 @@ export const LICENSE_COMPLIANCE_HELP_PATH = helpPagePath( 'user/compliance/license_compliance/index', ); +export const SCANNER_NAMES_MAP = { + SAST: SAST_SHORT_NAME, + SAST_IAC: SAST_IAC_NAME, + DAST: DAST_SHORT_NAME, + API_FUZZING: API_FUZZING_NAME, + CONTAINER_SCANNING: CONTAINER_SCANNING_NAME, + CLUSTER_IMAGE_SCANNING: CLUSTER_IMAGE_SCANNING_NAME, + COVERAGE_FUZZING: COVERAGE_FUZZING_NAME, + SECRET_DETECTION: SECRET_DETECTION_NAME, + DEPENDENCY_SCANNING: DEPENDENCY_SCANNING_NAME, +}; + export const securityFeatures = [ { name: SAST_NAME, @@ -156,27 +169,23 @@ export const securityFeatures = [ // https://gitlab.com/gitlab-org/gitlab/-/issues/331621 canEnableByMergeRequest: true, }, - ...(gon?.features?.configureIacScanningViaMr - ? [ - { - name: SAST_IAC_NAME, - shortName: SAST_IAC_SHORT_NAME, - description: SAST_IAC_DESCRIPTION, - helpPath: SAST_IAC_HELP_PATH, - configurationHelpPath: SAST_IAC_CONFIG_HELP_PATH, - type: REPORT_TYPE_SAST_IAC, + { + name: SAST_IAC_NAME, + shortName: SAST_IAC_SHORT_NAME, + description: SAST_IAC_DESCRIPTION, + helpPath: SAST_IAC_HELP_PATH, + configurationHelpPath: SAST_IAC_CONFIG_HELP_PATH, + type: REPORT_TYPE_SAST_IAC, - // This field is currently hardcoded because SAST IaC is always available. - // It will eventually come from the Backend, the progress is tracked in - // https://gitlab.com/gitlab-org/gitlab/-/issues/331622 - available: true, + // This field is currently hardcoded because SAST IaC is always available. + // It will eventually come from the Backend, the progress is tracked in + // https://gitlab.com/gitlab-org/gitlab/-/issues/331622 + available: true, - // This field will eventually come from the backend, the progress is - // tracked in https://gitlab.com/gitlab-org/gitlab/-/issues/331621 - canEnableByMergeRequest: true, - }, - ] - : []), + // This field will eventually come from the backend, the progress is + // tracked in https://gitlab.com/gitlab-org/gitlab/-/issues/331621 + canEnableByMergeRequest: true, + }, { name: DAST_NAME, shortName: DAST_SHORT_NAME, @@ -278,21 +287,17 @@ export const featureToMutationMap = { }, }), }, - ...(gon?.features?.configureIacScanningViaMr - ? { - [REPORT_TYPE_SAST_IAC]: { - mutationId: 'configureSastIac', - getMutationPayload: (projectPath) => ({ - mutation: configureSastIacMutation, - variables: { - input: { - projectPath, - }, - }, - }), + [REPORT_TYPE_SAST_IAC]: { + mutationId: 'configureSastIac', + getMutationPayload: (projectPath) => ({ + mutation: configureSastIacMutation, + variables: { + input: { + projectPath, }, - } - : {}), + }, + }), + }, [REPORT_TYPE_SECRET_DETECTION]: { mutationId: 'configureSecretDetection', getMutationPayload: (projectPath) => ({ diff --git a/app/assets/javascripts/security_configuration/components/training_provider_list.vue b/app/assets/javascripts/security_configuration/components/training_provider_list.vue new file mode 100644 index 00000000000..509377a63e8 --- /dev/null +++ b/app/assets/javascripts/security_configuration/components/training_provider_list.vue @@ -0,0 +1,61 @@ +<script> +import { GlCard, GlToggle, GlLink, GlSkeletonLoader } from '@gitlab/ui'; +import securityTrainingProvidersQuery from '../graphql/security_training_providers.query.graphql'; + +export default { + components: { + GlCard, + GlToggle, + GlLink, + GlSkeletonLoader, + }, + apollo: { + securityTrainingProviders: { + query: securityTrainingProvidersQuery, + }, + }, + data() { + return { + securityTrainingProviders: [], + }; + }, + computed: { + isLoading() { + return this.$apollo.queries.securityTrainingProviders.loading; + }, + }, +}; +</script> + +<template> + <div + v-if="isLoading" + class="gl-bg-white gl-py-6 gl-rounded-base gl-border-1 gl-border-solid gl-border-gray-100" + > + <gl-skeleton-loader :width="350" :height="44"> + <rect width="200" height="8" x="10" y="0" rx="4" /> + <rect width="300" height="8" x="10" y="15" rx="4" /> + <rect width="100" height="8" x="10" y="35" rx="4" /> + </gl-skeleton-loader> + </div> + <ul v-else class="gl-list-style-none gl-m-0 gl-p-0"> + <li + v-for="{ id, isEnabled, name, description, url } in securityTrainingProviders" + :key="id" + class="gl-mb-6" + > + <gl-card> + <div class="gl-display-flex"> + <gl-toggle :value="isEnabled" :label="__('Training mode')" label-position="hidden" /> + <div class="gl-ml-5"> + <h3 class="gl-font-lg gl-m-0 gl-mb-2">{{ name }}</h3> + <p> + {{ description }} + <gl-link :href="url" target="_blank">{{ __('Learn more.') }}</gl-link> + </p> + </div> + </div> + </gl-card> + </li> + </ul> +</template> diff --git a/app/assets/javascripts/security_configuration/graphql/security_training_providers.query.graphql b/app/assets/javascripts/security_configuration/graphql/security_training_providers.query.graphql new file mode 100644 index 00000000000..e0c5715ba8e --- /dev/null +++ b/app/assets/javascripts/security_configuration/graphql/security_training_providers.query.graphql @@ -0,0 +1,9 @@ +query Query { + securityTrainingProviders @client { + name + id + description + isEnabled + url + } +} diff --git a/app/assets/javascripts/security_configuration/index.js b/app/assets/javascripts/security_configuration/index.js index a8623b468f2..c86ff1a58f2 100644 --- a/app/assets/javascripts/security_configuration/index.js +++ b/app/assets/javascripts/security_configuration/index.js @@ -2,10 +2,39 @@ import Vue from 'vue'; import VueApollo from 'vue-apollo'; import createDefaultClient from '~/lib/graphql'; import { parseBooleanDataAttributes } from '~/lib/utils/dom_utils'; +import { __ } from '~/locale'; import SecurityConfigurationApp from './components/app.vue'; import { securityFeatures, complianceFeatures } from './components/constants'; import { augmentFeatures } from './utils'; +// Note: this is behind a feature flag and only a placeholder +// until the actual GraphQL fields have been added +// https://gitlab.com/gitlab-org/gi tlab/-/issues/346480 +export const tempResolvers = { + Query: { + securityTrainingProviders() { + return [ + { + __typename: 'SecurityTrainingProvider', + id: 101, + name: __('Kontra'), + description: __('Interactive developer security education.'), + url: 'https://application.security/', + isEnabled: false, + }, + { + __typename: 'SecurityTrainingProvider', + id: 102, + name: __('SecureCodeWarrior'), + description: __('Security training with guide and learning pathways.'), + url: 'https://www.securecodewarrior.com/', + isEnabled: true, + }, + ]; + }, + }, +}; + export const initSecurityConfiguration = (el) => { if (!el) { return null; @@ -14,7 +43,7 @@ export const initSecurityConfiguration = (el) => { Vue.use(VueApollo); const apolloProvider = new VueApollo({ - defaultClient: createDefaultClient(), + defaultClient: createDefaultClient(tempResolvers), }); const { diff --git a/app/assets/javascripts/security_configuration/utils.js b/app/assets/javascripts/security_configuration/utils.js index ec6b93c6193..47231497b8f 100644 --- a/app/assets/javascripts/security_configuration/utils.js +++ b/app/assets/javascripts/security_configuration/utils.js @@ -1,4 +1,5 @@ import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils'; +import { SCANNER_NAMES_MAP } from '~/security_configuration/components/constants'; export const augmentFeatures = (securityFeatures, complianceFeatures, features = []) => { const featuresByType = features.reduce((acc, feature) => { @@ -24,3 +25,13 @@ export const augmentFeatures = (securityFeatures, complianceFeatures, features = augmentedComplianceFeatures: complianceFeatures.map((feature) => augmentFeature(feature)), }; }; + +/** + * Converts a list of security scanner IDs (such as SAST_IAC) into a list of their translated + * names defined in the SCANNER_NAMES_MAP constant (eg. IaC Scanning). + * + * @param {String[]} scannerNames + * @returns {String[]} + */ +export const translateScannerNames = (scannerNames = []) => + scannerNames.map((scannerName) => SCANNER_NAMES_MAP[scannerName] || scannerName); |