Commit 0b3b9637 authored by Evan Read's avatar Evan Read

Refactor compliance framework UI and documentation

Changelog: other
EE: true
parent 86541261
......@@ -81,8 +81,8 @@ export default {
},
},
i18n: {
fullDescription: __('Choose any color. Or you can choose one of the suggested colors below'),
shortDescription: __('Choose any color'),
fullDescription: __('Enter any color or choose one of the suggested colors below.'),
shortDescription: __('Enter any color.'),
},
};
</script>
......
......@@ -39,17 +39,19 @@ You can use [emphasis](../../markdown.md#emphasis), [links](../../markdown.md#li
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/276221) in GitLab 13.9.
> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/287779) in GitLab 13.12.
You can create a framework label to identify that your project has certain compliance requirements
or needs additional oversight.
You can create a compliance framework label to identify that your project has certain compliance
requirements or needs additional oversight. The label can optionally apply
[compliance pipeline configuration](#compliance-pipeline-configuration).
Group owners can create, edit, and delete compliance frameworks:
1. Go to the group's **Settings** > **General**.
1. On the top bar, select **Menu > Groups** and find your group.
1. On the left sidebar, select **Settings** > **General**.
1. Expand the **Compliance frameworks** section.
Compliance frameworks created can then be assigned to any number of projects using:
Compliance frameworks created can then be assigned to projects within the group using:
- The project settings page inside the group or subgroups.
- The GitLab UI, using the project settings page.
- In [GitLab 14.2](https://gitlab.com/gitlab-org/gitlab/-/issues/333249) and later, using the
[GraphQL API](../../../api/graphql/reference/index.md#mutationprojectsetcomplianceframework).
......@@ -64,24 +66,32 @@ read-only view to discourage this behavior.
> - [Enabled by default](https://gitlab.com/gitlab-org/gitlab/-/issues/300324) in GitLab 13.11.
> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/331231) in GitLab 14.2.
Group owners can use the compliance pipeline configuration to define compliance requirements
such as scans or tests, and enforce them in individual projects.
Group owners can use compliance pipeline configuration to add additional pipeline configuration to
projects to define compliance requirements such as scans or tests.
The [custom compliance framework](#compliance-frameworks) feature allows group owners to specify the location
of a compliance pipeline configuration stored and managed in a dedicated project, distinct from a developer's project.
[Compliance frameworks](#compliance-frameworks) allow group owners to specify the location of
compliance pipeline configuration stored and managed in dedicated projects, separate from regular
projects.
When you set up the compliance pipeline configuration field, use the
`file@group/project` format. For example, you can configure
`.compliance-gitlab-ci.yml@compliance-group/compliance-project`.
This field is inherited by projects where the compliance framework label is applied. The result
forces the project to run the compliance configurations.
When you set up the compliance framework, use the **Compliance pipeline configuration** box to link
the compliance framework to specific CI/CD configuration. Use the
`path/file.y[a]ml@group-name/project-name` format. For example:
When a project with a custom label executes a pipeline, it begins by evaluating the compliance pipeline configuration.
The custom pipeline configuration can then execute any included individual project configuration.
- `.compliance-ci.yml@gitlab-org/gitlab`.
- `.compliance-ci.yaml@gitlab-org/gitlab`.
The user running the pipeline in the project should at least have Reporter access to the compliance project.
This configuration is inherited by projects where the compliance framework label is applied. The
result forces projects with the label to run the compliance CI/CD configuration in addition to
the project's own CI/CD configuration. When a project with a compliance framework label executes a
pipeline, it evaluates configuration in the following order:
Example `.compliance-gitlab-ci.yml`
1. Compliance pipeline configuration.
1. Project-specific pipeline configuration.
The user running the pipeline in the project must at least have the Reporter role on the compliance
project.
Example `.compliance-gitlab-ci.yml`:
```yaml
# Allows compliance team to control the ordering and interweaving of stages/jobs.
......@@ -94,10 +104,10 @@ stages:
- deploy
- post-compliance
variables: # Can be overridden by setting a job-specific variable in project's local .gitlab-ci.yml
variables: # Can be overridden by setting a job-specific variable in project's local .gitlab-ci.yml
FOO: sast
sast: # None of these attributes can be overridden by a project's local .gitlab-ci.yml
sast: # None of these attributes can be overridden by a project's local .gitlab-ci.yml
variables:
FOO: sast
image: ruby:2.6
......@@ -144,10 +154,10 @@ audit trail:
after_script:
- "# No after scripts."
include: # Execute individual project's configuration (if project contains .gitlab-ci.yml)
include: # Execute individual project's configuration (if project contains .gitlab-ci.yml)
project: '$CI_PROJECT_PATH'
file: '$CI_CONFIG_PATH'
ref: '$CI_COMMIT_REF_NAME' # Must be defined or MR pipelines always use the use default branch.
ref: '$CI_COMMIT_REF_NAME' # Must be defined or MR pipelines always use the use default branch.
```
##### Ensure compliance jobs are always run
......
......@@ -19,10 +19,8 @@ export default {
},
},
i18n: {
heading: s__('ComplianceFrameworks|There are no compliance frameworks set up yet'),
description: s__(
'ComplianceFrameworks|Once a compliance framework is added it will appear here.',
),
heading: s__('ComplianceFrameworks|No compliance frameworks are configured'),
description: s__('ComplianceFrameworks|Configured compliance frameworks appear here.'),
addButton: s__('ComplianceFrameworks|Add framework'),
},
};
......
......@@ -4,7 +4,7 @@ import { debounce } from 'lodash';
import { helpPagePath } from '~/helpers/help_page_helper';
import { validateHexColor } from '~/lib/utils/color_utils';
import { __, s__ } from '~/locale';
import { s__ } from '~/locale';
import ColorPicker from '~/vue_shared/components/color_picker/color_picker.vue';
import { DEBOUNCE_DELAY } from '../constants';
import { fetchPipelineConfigurationFileExists, validatePipelineConfirmationFormat } from '../utils';
......@@ -102,8 +102,10 @@ export default {
return this.$options.i18n.pipelineConfigurationInputUnknownFile;
},
scopedLabelsHelpPath() {
return helpPagePath('user/project/labels.md', { anchor: 'scoped-labels' });
compliancePipelineConfigurationHelpPath() {
return helpPagePath('user/project/settings/index.md', {
anchor: 'compliance-pipeline-configuration',
});
},
},
async created() {
......@@ -127,30 +129,20 @@ export default {
}, DEBOUNCE_DELAY),
},
i18n: {
titleInputLabel: __('Title'),
titleInputDescription: s__(
'ComplianceFrameworks|Use %{codeStart}::%{codeEnd} to create a %{linkStart}scoped set%{linkEnd} (eg. %{codeStart}SOX::AWS%{codeEnd})',
),
titleInputInvalid: __('A title is required'),
descriptionInputLabel: __('Description'),
descriptionInputInvalid: __('A description is required'),
titleInputLabel: s__('ComplianceFrameworks|Name'),
titleInputInvalid: s__('ComplianceFrameworks|Name is required'),
descriptionInputLabel: s__('ComplianceFrameworks|Description'),
descriptionInputInvalid: s__('ComplianceFrameworks|Description is required'),
pipelineConfigurationInputLabel: s__(
'ComplianceFrameworks|Compliance pipeline configuration location (optional)',
),
pipelineConfigurationInputSubLabel: s__(
'ComplianceFrameworks|Combines with the CI configuration at runtime.',
'ComplianceFrameworks|Compliance pipeline configuration (optional)',
),
pipelineConfigurationInputDescription: s__(
'ComplianceFrameworks|e.g. include-gitlab.ci.yml@group-name/project-name',
),
pipelineConfigurationInputInvalidFormat: s__(
'ComplianceFrameworks|Invalid format: it should follow the format [PATH].y(a)ml@[GROUP]/[PROJECT]',
'ComplianceFrameworks|Required format: %{codeStart}path/file.y[a]ml@group-name/project-name%{codeEnd}. %{linkStart}Learn more.%{linkEnd}',
),
pipelineConfigurationInputUnknownFile: s__(
'ComplianceFrameworks|Could not find this configuration location, please try a different location',
),
colorInputLabel: __('Background color'),
cancelBtnText: __('Cancel'),
pipelineConfigurationInputInvalidFormat: s__('ComplianceFrameworks|Invalid format'),
pipelineConfigurationInputUnknownFile: s__('ComplianceFrameworks|Configuration not found'),
colorInputLabel: s__('ComplianceFrameworks|Background color'),
cancelBtnText: s__('ComplianceFrameworks|Cancel'),
},
};
</script>
......@@ -162,18 +154,6 @@ export default {
:state="isValidName"
data-testid="name-input-group"
>
<template #description>
<gl-sprintf :message="$options.i18n.titleInputDescription">
<template #code="{ content }">
<code>{{ content }}</code>
</template>
<template #link="{ content }">
<gl-link :href="scopedLabelsHelpPath" target="_blank">{{ content }}</gl-link>
</template>
</gl-sprintf>
</template>
<gl-form-input
:value="name"
:state="isValidName"
......@@ -199,14 +179,24 @@ export default {
<gl-form-group
v-if="pipelineConfigurationFullPathEnabled"
:label="$options.i18n.pipelineConfigurationInputLabel"
:description="$options.i18n.pipelineConfigurationInputDescription"
:invalid-feedback="pipelineConfigurationFeedbackMessage"
:state="isValidPipelineConfiguration"
data-testid="pipeline-configuration-input-group"
>
<p class="col-form-label gl-font-weight-normal!">
{{ $options.i18n.pipelineConfigurationInputSubLabel }}
</p>
<template #description>
<gl-sprintf :message="$options.i18n.pipelineConfigurationInputDescription">
<template #code="{ content }">
<code>{{ content }}</code>
</template>
<template #link="{ content }">
<gl-link :href="compliancePipelineConfigurationHelpPath" target="_blank">{{
content
}}</gl-link>
</template>
</gl-sprintf>
</template>
<gl-form-input
:value="pipelineConfigurationFullPath"
:state="isValidPipelineConfiguration"
......
......@@ -5,7 +5,7 @@
.settings-header
%h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only= _('Compliance framework')
%button.btn.gl-button.btn-default.js-settings-toggle{ type: 'button' }= expanded ? _('Collapse') : _('Expand')
%p= html_escape(_('Select a framework that applies to this project. %{linkStart}How are these added?%{linkEnd}')) % { linkStart: compliance_framework_doc_link, linkEnd: '</a>'.html_safe }
%p= html_escape(_('Select a compliance framework to apply to this project. %{linkStart}Learn more.%{linkEnd}')) % { linkStart: compliance_framework_doc_link, linkEnd: '</a>'.html_safe }
.settings-content
= form_for @project, html: { multipart: true, class: "compliance-framework-form" }, authenticity_token: true do |f|
......
- expanded = expanded_by_default?
- compliance_framework_doc_link = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: help_page_path('user/project/settings/index.md', anchor: 'compliance-frameworks') }
- if show_compliance_frameworks?(@group)
%section.settings.no-animate#js-compliance-frameworks-settings{ class: ('expanded' if expanded) }
......@@ -8,6 +9,6 @@
%button.btn.gl-button.js-settings-toggle{ type: 'button' }
= expanded ? _('Collapse') : _('Expand')
%p
= s_('GroupSettings|Configure frameworks to apply enforceable rules to projects.')
= html_escape(s_('GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}Learn more.%{linkEnd}')) % { linkStart: compliance_framework_doc_link, linkEnd: '</a>'.html_safe }
.settings-content
#js-compliance-frameworks-list{ data: compliance_frameworks_list_data(@group) }
- add_to_breadcrumbs _('General Settings'), edit_group_path(@group)
- title = s_('ComplianceFramework|Edit Compliance Framework')
- title = s_('ComplianceFramework|Edit compliance framework')
- page_title title
%h3.page-title= title
......
- add_to_breadcrumbs _('General Settings'), edit_group_path(@group)
- title = s_('ComplianceFramework|New Compliance Framework')
- title = s_('ComplianceFramework|New compliance framework')
- page_title title
%h3.page-title= title
......
......@@ -25,8 +25,8 @@ describe('ListEmptyState', () => {
createComponent();
expect(findEmptyState().props()).toMatchObject({
title: 'There are no compliance frameworks set up yet',
description: 'Once a compliance framework is added it will appear here.',
title: 'No compliance frameworks are configured',
description: 'Configured compliance frameworks appear here.',
svgPath: 'dir/image.svg',
primaryButtonLink: 'group/framework/new',
primaryButtonText: 'Add framework',
......
......@@ -63,12 +63,6 @@ describe('SharedForm', () => {
expect(findCancelBtn()).toExist();
});
it('shows the name input description', () => {
wrapper = createComponent();
expect(findNameGroup().text()).toContain('Use :: to create a scoped set (eg. SOX::AWS)');
});
it('sets the submit button text from the property', () => {
wrapper = createComponent();
......@@ -112,8 +106,8 @@ describe('SharedForm', () => {
it.each`
pipelineConfigurationFullPath | message
${'foobar'} | ${'Invalid format: it should follow the format [PATH].y(a)ml@[GROUP]/[PROJECT]'}
${'foo.yml@bar/baz'} | ${'Could not find this configuration location, please try a different location'}
${'foobar'} | ${'Invalid format'}
${'foo.yml@bar/baz'} | ${'Configuration not found'}
`(
'sets the correct invalid message to the group',
async ({ pipelineConfigurationFullPath, message }) => {
......
......@@ -18,7 +18,7 @@ RSpec.describe 'compliance_management/compliance_framework/_project_settings.htm
it 'shows the section description' do
render
expect(rendered).to have_text 'Select a framework that applies to this project. How are these added?'
expect(rendered).to have_text 'Select a compliance framework to apply to this project. Learn more.'
end
context 'group has compliance frameworks' do
......
......@@ -6,7 +6,7 @@ RSpec.describe 'groups/_compliance_frameworks.html.haml' do
let_it_be(:group) { build(:group) }
let(:title) { 'Compliance frameworks' }
let(:description) { 'Configure frameworks to apply enforceable rules to projects.' }
let(:description) { 'Configure compliance frameworks to make them available to projects in this group.' }
before do
assign(:group, group)
......
......@@ -18,7 +18,7 @@ RSpec.describe 'groups/compliance_frameworks/edit.html.haml' do
it 'shows the compliance frameworks form', :aggregate_failures do
render
expect(rendered).to have_content('Edit Compliance Framework')
expect(rendered).to have_content('Edit compliance framework')
expect(rendered).to have_css('#js-compliance-frameworks-form')
expect(rendered).to have_css('[data-framework-id="1"]')
end
......
......@@ -17,7 +17,7 @@ RSpec.describe 'groups/compliance_frameworks/new.html.haml' do
it 'shows the compliance frameworks form', :aggregate_failures do
render
expect(rendered).to have_content('New Compliance Framework')
expect(rendered).to have_content('New compliance framework')
expect(rendered).to have_css('#js-compliance-frameworks-form')
end
end
......@@ -1439,9 +1439,6 @@ msgstr ""
msgid "A deleted user"
msgstr ""
msgid "A description is required"
msgstr ""
msgid "A different reason"
msgstr ""
......@@ -6838,15 +6835,9 @@ msgstr ""
msgid "Choose a type..."
msgstr ""
msgid "Choose any color"
msgstr ""
msgid "Choose any color."
msgstr ""
msgid "Choose any color. Or you can choose one of the suggested colors below"
msgstr ""
msgid "Choose file…"
msgstr ""
......@@ -8493,16 +8484,22 @@ msgstr ""
msgid "ComplianceFrameworks|Add framework"
msgstr ""
msgid "ComplianceFrameworks|Combines with the CI configuration at runtime."
msgid "ComplianceFrameworks|Background color"
msgstr ""
msgid "ComplianceFrameworks|Cancel"
msgstr ""
msgid "ComplianceFrameworks|Compliance framework deleted successfully"
msgstr ""
msgid "ComplianceFrameworks|Compliance pipeline configuration location (optional)"
msgid "ComplianceFrameworks|Compliance pipeline configuration (optional)"
msgstr ""
msgid "ComplianceFrameworks|Configuration not found"
msgstr ""
msgid "ComplianceFrameworks|Could not find this configuration location, please try a different location"
msgid "ComplianceFrameworks|Configured compliance frameworks appear here."
msgstr ""
msgid "ComplianceFrameworks|Delete compliance framework %{framework}"
......@@ -8511,6 +8508,12 @@ msgstr ""
msgid "ComplianceFrameworks|Delete framework"
msgstr ""
msgid "ComplianceFrameworks|Description"
msgstr ""
msgid "ComplianceFrameworks|Description is required"
msgstr ""
msgid "ComplianceFrameworks|Edit framework"
msgstr ""
......@@ -8523,31 +8526,31 @@ msgstr ""
msgid "ComplianceFrameworks|Error fetching compliance frameworks data. Please refresh the page or try a different framework"
msgstr ""
msgid "ComplianceFrameworks|Invalid format: it should follow the format [PATH].y(a)ml@[GROUP]/[PROJECT]"
msgid "ComplianceFrameworks|Invalid format"
msgstr ""
msgid "ComplianceFrameworks|Once a compliance framework is added it will appear here."
msgid "ComplianceFrameworks|Name"
msgstr ""
msgid "ComplianceFrameworks|There are no compliance frameworks set up yet"
msgid "ComplianceFrameworks|Name is required"
msgstr ""
msgid "ComplianceFrameworks|Unable to save this compliance framework. Please try again"
msgid "ComplianceFrameworks|No compliance frameworks are configured"
msgstr ""
msgid "ComplianceFrameworks|Use %{codeStart}::%{codeEnd} to create a %{linkStart}scoped set%{linkEnd} (eg. %{codeStart}SOX::AWS%{codeEnd})"
msgid "ComplianceFrameworks|Required format: %{codeStart}path/file.y[a]ml@group-name/project-name%{codeEnd}. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
msgid "ComplianceFrameworks|You are about to permanently delete the compliance framework %{framework} from all projects which currently have it applied, which may remove other functionality. This cannot be undone."
msgid "ComplianceFrameworks|Unable to save this compliance framework. Please try again"
msgstr ""
msgid "ComplianceFrameworks|e.g. include-gitlab.ci.yml@group-name/project-name"
msgid "ComplianceFrameworks|You are about to permanently delete the compliance framework %{framework} from all projects which currently have it applied, which may remove other functionality. This cannot be undone."
msgstr ""
msgid "ComplianceFramework|Edit Compliance Framework"
msgid "ComplianceFramework|Edit compliance framework"
msgstr ""
msgid "ComplianceFramework|New Compliance Framework"
msgid "ComplianceFramework|New compliance framework"
msgstr ""
msgid "Component"
......@@ -12823,6 +12826,12 @@ msgstr ""
msgid "Enter an integer number number between 0 and 100"
msgstr ""
msgid "Enter any color or choose one of the suggested colors below."
msgstr ""
msgid "Enter any color."
msgstr ""
msgid "Enter at least three characters to search"
msgstr ""
......@@ -16408,7 +16417,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr ""
msgid "GroupSettings|Configure frameworks to apply enforceable rules to projects."
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
msgid "GroupSettings|Custom project templates"
......@@ -30535,10 +30544,10 @@ msgstr ""
msgid "Select a branch"
msgstr ""
msgid "Select a file from the left sidebar to begin editing. Afterwards, you'll be able to commit your changes."
msgid "Select a compliance framework to apply to this project. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
msgid "Select a framework that applies to this project. %{linkStart}How are these added?%{linkEnd}"
msgid "Select a file from the left sidebar to begin editing. Afterwards, you'll be able to commit your changes."
msgstr ""
msgid "Select a group to invite"
......
......@@ -111,15 +111,13 @@ describe('ColorPicker', () => {
gon.suggested_label_colors = {};
createComponent(shallowMount);
expect(description()).toBe('Choose any color');
expect(description()).toBe('Enter any color.');
expect(presetColors().exists()).toBe(false);
});
it('shows the suggested colors', () => {
createComponent(shallowMount);
expect(description()).toBe(
'Choose any color. Or you can choose one of the suggested colors below',
);
expect(description()).toBe('Enter any color or choose one of the suggested colors below.');
expect(presetColors()).toHaveLength(4);
});
......
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