Commit 4297f002 authored by Mark Florian's avatar Mark Florian Committed by Nicolò Maria Mezzopera

Link to CI file history in Security Configuration

Addresses https://gitlab.com/gitlab-org/gitlab/-/issues/220578.
parent 63124283
......@@ -15,18 +15,22 @@ The Security Configuration page displays the configuration state of each securit
current project.
To view a project's security configuration, go to the project's home page,
then in the left sidebar, go to **Security & Compliance** > **Configuration**.
then in the left sidebar go to **Security & Compliance > Configuration**.
## Status
For each security control the page displays:
- **Status** - Status of the security control: enabled, not enabled, or available.
- **Manage** - A management option or a link to the documentation.
For each security control, the page displays the status and either a management option or a
documentation link.
## Status
The status of each security control is determined by the project's latest default branch
[CI pipeline](../../../ci/pipelines/index.md).
If a job with the expected security report artifact exists in the pipeline, the feature's status is
_enabled_.
For SAST, click **View history** to see the `.gitlab-ci.yml` file’s history.
NOTE: **Note:**
If the latest pipeline used [Auto DevOps](../../../topics/autodevops/index.md),
all security features are configured by default.
......
......@@ -5,6 +5,7 @@ import { s__, __ } from '~/locale';
import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import AutoFixSettings from './auto_fix_settings.vue';
import FeatureStatus from './feature_status.vue';
import ManageFeature from './manage_feature.vue';
export default {
......@@ -15,6 +16,7 @@ export default {
GlTable,
AutoFixSettings,
LocalStorageSync,
FeatureStatus,
ManageFeature,
},
mixins: [glFeatureFlagsMixin()],
......@@ -50,6 +52,11 @@ export default {
required: false,
default: false,
},
gitlabCiHistoryPath: {
type: String,
required: false,
default: '',
},
autoDevopsPath: {
type: String,
required: false,
......@@ -167,6 +174,14 @@ export default {
</div>
</template>
<template #cell(status)="{ item }">
<feature-status
:feature="item"
:gitlab-ci-present="gitlabCiPresent"
:gitlab-ci-history-path="gitlabCiHistoryPath"
/>
</template>
<template #cell(manage)="{ item }">
<manage-feature
:feature="item"
......
<script>
import { GlLink } from '@gitlab/ui';
export default {
components: {
GlLink,
},
props: {
feature: {
type: Object,
required: true,
},
gitlabCiPresent: {
type: Boolean,
required: false,
default: false,
},
gitlabCiHistoryPath: {
type: String,
required: false,
default: '',
},
},
computed: {
canViewCiHistory() {
const { type, configured } = this.feature;
return type === 'sast' && configured && this.gitlabCiPresent;
},
},
};
</script>
<template>
<div>
{{ feature.status }}
<template v-if="canViewCiHistory">
<br />
<gl-link :href="gitlabCiHistoryPath">{{ s__('SecurityConfiguration|View history') }}</gl-link>
</template>
</div>
</template>
......@@ -17,6 +17,7 @@ export default function init() {
dependencyScanningHelpPath,
toggleAutofixSettingEndpoint,
createSastMergeRequestPath,
gitlabCiHistoryPath,
} = el.dataset;
return new Vue({
......@@ -38,6 +39,7 @@ export default function init() {
'canEnableAutoDevops',
'gitlabCiPresent',
]),
gitlabCiHistoryPath,
autoFixSettingsProps: {
autoFixEnabled: JSON.parse(autoFixEnabled),
autoFixHelpPath,
......
......@@ -62,6 +62,7 @@ module Projects
auto_fix_enabled: autofix_enabled,
can_toggle_auto_fix_settings: auto_fix_permission,
gitlab_ci_present: gitlab_ci_present?,
gitlab_ci_history_path: gitlab_ci_history_path,
auto_fix_user_path: '/' # TODO: real link will be updated with https://gitlab.com/gitlab-org/gitlab/-/issues/215669
}
end
......@@ -93,6 +94,11 @@ module Projects
latest_pipeline.try(:config_path) == Gitlab::FileDetector::PATTERNS[:gitlab_ci]
end
def gitlab_ci_history_path
gitlab_ci = Gitlab::FileDetector::PATTERNS[:gitlab_ci]
Gitlab::Routing.url_helpers.project_blame_path(project, File.join(project.default_branch, gitlab_ci))
end
def features
scans = scan_types.map do |scan_type|
if scanner_enabled?(scan_type)
......
---
title: Add link to GitLab CI history in Security Configuration
merge_request: 41673
author:
type: added
......@@ -2,6 +2,7 @@ import { mount } from '@vue/test-utils';
import { merge } from 'lodash';
import { GlAlert, GlLink } from '@gitlab/ui';
import SecurityConfigurationApp from 'ee/security_configuration/components/app.vue';
import FeatureStatus from 'ee/security_configuration/components/feature_status.vue';
import ManageFeature from 'ee/security_configuration/components/manage_feature.vue';
import stubChildren from 'helpers/stub_children';
import { useLocalStorageSpy } from 'helpers/local_storage_helper';
......@@ -16,6 +17,7 @@ const propsData = {
autoDevopsPath: 'http://autoDevopsPath',
helpPagePath: 'http://helpPagePath',
gitlabCiPresent: false,
gitlabCiHistoryPath: '/ci/history',
autoFixSettingsProps: {},
createSastMergeRequestPath: 'http://createSastMergeRequestPath',
};
......@@ -173,27 +175,17 @@ describe('Security Configuration App', () => {
const { feature, status, manage } = getRowCells(rows.at(i));
expect(feature.text()).toMatch(features[i].name);
expect(feature.text()).toMatch(features[i].description);
expect(status.text()).toMatch(features[i].configured ? 'Enabled' : 'Not enabled');
expect(manage.find(ManageFeature).props()).toMatchObject({
expect(status.find(FeatureStatus).props()).toEqual({
feature: features[i],
gitlabCiPresent: propsData.gitlabCiPresent,
gitlabCiHistoryPath: propsData.gitlabCiHistoryPath,
});
expect(manage.find(ManageFeature).props()).toEqual({
feature: features[i],
autoDevopsEnabled: propsData.autoDevopsEnabled,
createSastMergeRequestPath: propsData.createSastMergeRequestPath,
});
}
});
describe('given a feature enabled by Auto DevOps', () => {
it('displays the expected status text', () => {
const features = generateFeatures(1, {
configured: true,
status: 'Enabled with Auto DevOps',
});
createComponent({ propsData: { features, autoDevopsEnabled: true } });
const { status } = getRowCells(getFeaturesRows().at(0));
expect(status.text()).toMatch('Enabled with Auto DevOps');
});
});
});
});
import { GlLink } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import FeatureStatus from 'ee/security_configuration/components/feature_status.vue';
import { generateFeatures } from './helpers';
const gitlabCiHistoryPath = '/ci/history';
describe('FeatureStatus component', () => {
let wrapper;
let feature;
const createComponent = options => {
wrapper = shallowMount(FeatureStatus, options);
};
afterEach(() => {
wrapper.destroy();
feature = undefined;
});
const findHistoryLink = () => wrapper.find(GlLink);
describe.each`
context | type | configured | gitlabCiPresent | shouldShowHistory
${'no CI with sast disabled'} | ${'sast'} | ${false} | ${false} | ${false}
${'CI with sast disabled'} | ${'sast'} | ${false} | ${true} | ${false}
${'no CI with sast enabled'} | ${'sast'} | ${true} | ${false} | ${false}
${'CI with foo enabled'} | ${'foo'} | ${true} | ${true} | ${false}
${'CI with sast enabled'} | ${'sast'} | ${true} | ${true} | ${true}
`('given $context', ({ type, configured, gitlabCiPresent, shouldShowHistory }) => {
beforeEach(() => {
[feature] = generateFeatures(1, { type, configured });
createComponent({
propsData: { feature, gitlabCiPresent, gitlabCiHistoryPath },
});
});
it('shows feature status text', () => {
expect(wrapper.text()).toContain(feature.status);
});
it(`${shouldShowHistory ? 'shows' : 'does not show'} the history link`, () => {
expect(findHistoryLink().exists()).toBe(shouldShowHistory);
});
if (shouldShowHistory) {
it("sets the link's href correctly", () => {
expect(findHistoryLink().attributes('href')).toBe(gitlabCiHistoryPath);
});
}
});
});
......@@ -37,6 +37,10 @@ RSpec.describe Projects::Security::ConfigurationPresenter do
expect(subject[:create_sast_merge_request_path]).to eq(project_security_configuration_sast_path(project))
end
it 'includes the path to gitlab_ci history' do
expect(subject[:gitlab_ci_history_path]).to eq(project_blame_path(project, 'master/.gitlab-ci.yml'))
end
context "when the latest default branch pipeline's source is auto devops" do
before do
pipeline = create(
......
......@@ -22091,6 +22091,9 @@ msgstr ""
msgid "SecurityConfiguration|Using custom settings. You won't receive automatic updates on this variable. %{anchorStart}Restore to default%{anchorEnd}"
msgstr ""
msgid "SecurityConfiguration|View history"
msgstr ""
msgid "SecurityConfiguration|You can quickly enable all security scanning tools by enabling %{linkStart}Auto DevOps%{linkEnd}."
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