Commit 855e13ca authored by GitLab Bot's avatar GitLab Bot

Automatic merge of gitlab-org/gitlab master

parents d0f5ddc0 0716b8a1
...@@ -65,33 +65,6 @@ ...@@ -65,33 +65,6 @@
display: inline; display: inline;
} }
.branch-link {
margin-bottom: 2px;
}
.limit-box {
cursor: pointer;
display: inline-flex;
align-items: center;
background-color: $red-100;
border-radius: $border-radius-default;
text-align: center;
&:hover {
background-color: $red-200;
}
.limit-icon {
margin: 0 4px;
}
.limit-message {
line-height: 16px;
margin-right: 8px;
font-size: 12px;
}
}
svg { svg {
vertical-align: text-top; vertical-align: text-top;
} }
......
...@@ -73,9 +73,7 @@ module CommitsHelper ...@@ -73,9 +73,7 @@ module CommitsHelper
# Returns a link formatted as a commit branch link # Returns a link formatted as a commit branch link
def commit_branch_link(url, text) def commit_branch_link(url, text)
link_to(url, class: 'badge badge-gray ref-name branch-link') do gl_badge_tag(text, { variant: :info, icon: 'branch' }, { href: url, class: 'gl-font-monospace gl-mb-1' })
sprite_icon('branch', size: 12, css_class: 'fork-svg') + "#{text}"
end
end end
# Returns the sorted alphabetically links to branches, separated by a comma # Returns the sorted alphabetically links to branches, separated by a comma
...@@ -87,9 +85,7 @@ module CommitsHelper ...@@ -87,9 +85,7 @@ module CommitsHelper
# Returns a link formatted as a commit tag link # Returns a link formatted as a commit tag link
def commit_tag_link(url, text) def commit_tag_link(url, text)
link_to(url, class: 'badge badge-gray ref-name') do gl_badge_tag(text, { variant: :info, icon: 'tag' }, { href: url, class: 'gl-font-monospace' })
sprite_icon('tag', size: 12, css_class: 'gl-mr-2 vertical-align-middle') + "#{text}"
end
end end
# Returns the sorted links to tags, separated by a comma # Returns the sorted links to tags, separated by a comma
......
.has-tooltip{ class: "limit-box limit-box-#{objects} gl-ml-2", data: { title: _('Project has too many %{label_for_message} to search') % { label_for_message: label_for_message } } } - icon = objects == :branch ? 'fork' : 'tag'
.limit-icon - text = _('%{label_for_message} unavailable') % { label_for_message: label_for_message.capitalize }
- if objects == :branch - tooltip_title = _('Project has too many %{label_for_message} to search') % { label_for_message: label_for_message }
= sprite_icon('fork', size: 12)
- else = gl_badge_tag(text, { variant: :danger, icon: icon }, { class: 'has-tooltip gl-ml-2', data: { title: tooltip_title } })
= sprite_icon('tag')
.limit-message
%span= _('%{label_for_message} unavailable') % { label_for_message: label_for_message.capitalize }
...@@ -6,8 +6,9 @@ ...@@ -6,8 +6,9 @@
- if @branches.any? || @tags.any? || @tags_limit_exceeded - if @branches.any? || @tags.any? || @tags_limit_exceeded
%span %span
= link_to "#", class: "js-details-expand badge badge-gray ref-name" do = gl_badge_tag(_("Expand"),
= sprite_icon('ellipsis_h', size: 12, css_class: 'vertical-align-middle') { variant: :info, icon: 'ellipsis_h', icon_only: true },
{ href: '#', class: 'js-details-expand gl-font-monospace' })
%span.js-details-content.hide %span.js-details-content.hide
= commit_branches_links(@project, @branches) = commit_branches_links(@project, @branches)
- if @tags_limit_exceeded - if @tags_limit_exceeded
......
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
.row .row
.form-group.col-sm-12 .form-group.col-sm-12
= f.label :role, _('Role'), class: 'label-bold' = f.label :role, _('Role'), class: 'label-bold'
= f.select :role, ::User.roles.keys.map { |role| [role.titleize, role] }, { include_blank: _('Select a role') }, class: 'form-control js-user-role-dropdown', autofocus: true, required: true = f.select :role, ::User.roles.keys.map { |role| [role.titleize, role] }, { include_blank: _('Select a role') }, class: 'form-control js-user-role-dropdown', autofocus: true, required: true, data: { qa_selector: 'role_dropdown' }
- if Feature.enabled?(:user_other_role_details) - if Feature.enabled?(:user_other_role_details)
.row .row
.form-group.col-sm-12.js-other-role-group.hidden .form-group.col-sm-12.js-other-role-group.hidden
......
...@@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56296 ...@@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56296
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/321948 rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/321948
milestone: '13.11' milestone: '13.11'
type: development type: development
group: group::access group: group::workspace
default_enabled: false default_enabled: false
...@@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/67652 ...@@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/67652
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/340159 rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/340159
milestone: '14.3' milestone: '14.3'
type: development type: development
group: group::access group: group::workspace
default_enabled: false default_enabled: false
...@@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/57137 ...@@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/57137
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/334952 rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/334952
milestone: '13.12' milestone: '13.12'
type: development type: development
group: group::access group: group::workspace
default_enabled: false default_enabled: false
...@@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/72662 ...@@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/72662
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/343619 rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/343619
milestone: '14.6' milestone: '14.6'
type: development type: development
group: group::access group: group::workspace
default_enabled: false default_enabled: false
...@@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/61163 ...@@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/61163
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/331907 rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/331907
milestone: '14.0' milestone: '14.0'
type: development type: development
group: group::access group: group::workspace
default_enabled: false default_enabled: false
...@@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/67650 ...@@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/67650
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/345666 rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/345666
milestone: '14.6' milestone: '14.6'
type: development type: development
group: group::access group: group::workspace
default_enabled: false default_enabled: false
...@@ -42,6 +42,13 @@ export const POLICY_TYPE_COMPONENT_OPTIONS = { ...@@ -42,6 +42,13 @@ export const POLICY_TYPE_COMPONENT_OPTIONS = {
urlParameter: 'scan_execution_policy', urlParameter: 'scan_execution_policy',
value: 'scanExecution', value: 'scanExecution',
}, },
scanResult: {
component: 'scan-result-policy-editor',
text: s__('SecurityOrchestration|Scan Result'),
typeName: 'ScanResultPolicy',
urlParameter: 'scan_result_policy',
value: 'scanResult',
},
}; };
export const POLICY_TYPE_OPTIONS = { export const POLICY_TYPE_OPTIONS = {
...@@ -53,6 +60,10 @@ export const POLICY_TYPE_OPTIONS = { ...@@ -53,6 +60,10 @@ export const POLICY_TYPE_OPTIONS = {
value: 'POLICY_TYPE_SCAN_EXECUTION', value: 'POLICY_TYPE_SCAN_EXECUTION',
text: s__('SecurityOrchestration|Scan execution'), text: s__('SecurityOrchestration|Scan execution'),
}, },
POLICY_TYPE_SCAN_RESULT: {
value: 'POLICY_TYPE_SCAN_RESULT',
text: s__('SecurityOrchestration|Scan result'),
},
ALL: { ALL: {
value: '', value: '',
text: s__('SecurityOrchestration|All policies'), text: s__('SecurityOrchestration|All policies'),
......
...@@ -14,8 +14,10 @@ import createFlash from '~/flash'; ...@@ -14,8 +14,10 @@ import createFlash from '~/flash';
import { getTimeago } from '~/lib/utils/datetime_utility'; import { getTimeago } from '~/lib/utils/datetime_utility';
import { setUrlFragment, mergeUrlParams } from '~/lib/utils/url_utility'; import { setUrlFragment, mergeUrlParams } from '~/lib/utils/url_utility';
import { __, s__ } from '~/locale'; import { __, s__ } from '~/locale';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import networkPoliciesQuery from '../../graphql/queries/network_policies.query.graphql'; import networkPoliciesQuery from '../../graphql/queries/network_policies.query.graphql';
import scanExecutionPoliciesQuery from '../../graphql/queries/scan_execution_policies.query.graphql'; import scanExecutionPoliciesQuery from '../../graphql/queries/scan_execution_policies.query.graphql';
import scanResultPoliciesQuery from '../../graphql/queries/scan_result_policies.query.graphql';
import { getPolicyType } from '../../utils'; import { getPolicyType } from '../../utils';
import { POLICY_TYPE_COMPONENT_OPTIONS, POLICY_TYPE_OPTIONS } from '../constants'; import { POLICY_TYPE_COMPONENT_OPTIONS, POLICY_TYPE_OPTIONS } from '../constants';
import EnvironmentPicker from '../environment_picker.vue'; import EnvironmentPicker from '../environment_picker.vue';
...@@ -57,6 +59,7 @@ export default { ...@@ -57,6 +59,7 @@ export default {
directives: { directives: {
GlTooltip: GlTooltipDirective, GlTooltip: GlTooltipDirective,
}, },
mixins: [glFeatureFlagMixin()],
inject: ['documentationPath', 'projectPath', 'newPolicyPath'], inject: ['documentationPath', 'projectPath', 'newPolicyPath'],
props: { props: {
shouldUpdatePolicyList: { shouldUpdatePolicyList: {
...@@ -100,12 +103,25 @@ export default { ...@@ -100,12 +103,25 @@ export default {
}, },
error: createPolicyFetchError, error: createPolicyFetchError,
}, },
scanResultPolicies: {
query: scanResultPoliciesQuery,
variables() {
return {
fullPath: this.projectPath,
};
},
update(data) {
return data?.project?.scanResultPolicies?.nodes ?? [];
},
error: createPolicyFetchError,
},
}, },
data() { data() {
return { return {
selectedPolicy: null, selectedPolicy: null,
networkPolicies: [], networkPolicies: [],
scanExecutionPolicies: [], scanExecutionPolicies: [],
scanResultPolicies: [],
selectedPolicyType: POLICY_TYPE_OPTIONS.ALL.value, selectedPolicyType: POLICY_TYPE_OPTIONS.ALL.value,
}; };
}, },
...@@ -113,10 +129,14 @@ export default { ...@@ -113,10 +129,14 @@ export default {
...mapState('threatMonitoring', ['allEnvironments', 'currentEnvironmentId', 'hasEnvironment']), ...mapState('threatMonitoring', ['allEnvironments', 'currentEnvironmentId', 'hasEnvironment']),
...mapGetters('threatMonitoring', ['currentEnvironmentGid']), ...mapGetters('threatMonitoring', ['currentEnvironmentGid']),
allPolicyTypes() { allPolicyTypes() {
return { const allTypes = {
[POLICY_TYPE_OPTIONS.POLICY_TYPE_NETWORK.value]: this.networkPolicies, [POLICY_TYPE_OPTIONS.POLICY_TYPE_NETWORK.value]: this.networkPolicies,
[POLICY_TYPE_OPTIONS.POLICY_TYPE_SCAN_EXECUTION.value]: this.scanExecutionPolicies, [POLICY_TYPE_OPTIONS.POLICY_TYPE_SCAN_EXECUTION.value]: this.scanExecutionPolicies,
}; };
if (this.isFeatureEnabled) {
allTypes[POLICY_TYPE_OPTIONS.POLICY_TYPE_SCAN_RESULT.value] = this.scanResultPolicies;
}
return allTypes;
}, },
documentationFullPath() { documentationFullPath() {
return setUrlFragment(this.documentationPath, 'container-network-policy'); return setUrlFragment(this.documentationPath, 'container-network-policy');
...@@ -141,7 +161,8 @@ export default { ...@@ -141,7 +161,8 @@ export default {
isLoadingPolicies() { isLoadingPolicies() {
return ( return (
this.$apollo.queries.networkPolicies.loading || this.$apollo.queries.networkPolicies.loading ||
this.$apollo.queries.scanExecutionPolicies.loading this.$apollo.queries.scanExecutionPolicies.loading ||
this.$apollo.queries.scanResultPolicies.loading
); );
}, },
hasSelectedPolicy() { hasSelectedPolicy() {
...@@ -207,11 +228,15 @@ export default { ...@@ -207,11 +228,15 @@ export default {
return fields; return fields;
}, },
isFeatureEnabled() {
return this.glFeatures.scanResultPolicy;
},
}, },
watch: { watch: {
shouldUpdatePolicyList(newShouldUpdatePolicyList) { shouldUpdatePolicyList(newShouldUpdatePolicyList) {
if (newShouldUpdatePolicyList) { if (newShouldUpdatePolicyList) {
this.$apollo.queries.scanExecutionPolicies.refetch(); this.$apollo.queries.scanExecutionPolicies.refetch();
this.$apollo.queries.scanResultPolicies.refetch();
this.$emit('update-policy-list', false); this.$emit('update-policy-list', false);
} }
}, },
......
<script> <script>
import { GlFormGroup, GlDropdown, GlDropdownItem } from '@gitlab/ui'; import { GlFormGroup, GlDropdown, GlDropdownItem } from '@gitlab/ui';
import { __ } from '~/locale'; import { __ } from '~/locale';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { POLICY_TYPE_OPTIONS } from './constants'; import { POLICY_TYPE_OPTIONS } from './constants';
export default { export default {
...@@ -10,6 +11,7 @@ export default { ...@@ -10,6 +11,7 @@ export default {
GlDropdown, GlDropdown,
GlDropdownItem, GlDropdownItem,
}, },
mixins: [glFeatureFlagMixin()],
props: { props: {
value: { value: {
type: String, type: String,
...@@ -24,6 +26,16 @@ export default { ...@@ -24,6 +26,16 @@ export default {
selectedValueText() { selectedValueText() {
return Object.values(POLICY_TYPE_OPTIONS).find(({ value }) => value === this.value).text; return Object.values(POLICY_TYPE_OPTIONS).find(({ value }) => value === this.value).text;
}, },
isFeatureEnabled() {
return this.glFeatures.scanResultPolicy;
},
policyTypeOptions() {
const policyType = POLICY_TYPE_OPTIONS;
if (!this.isFeatureEnabled) {
delete policyType.POLICY_TYPE_SCAN_RESULT;
}
return policyType;
},
}, },
methods: { methods: {
setPolicyType({ value }) { setPolicyType({ value }) {
...@@ -51,7 +63,7 @@ export default { ...@@ -51,7 +63,7 @@ export default {
:text="selectedValueText" :text="selectedValueText"
> >
<gl-dropdown-item <gl-dropdown-item
v-for="option in $options.POLICY_TYPE_OPTIONS" v-for="option in policyTypeOptions"
:key="option.value" :key="option.value"
:data-testid="`policy-type-${option.value}-option`" :data-testid="`policy-type-${option.value}-option`"
@click="setPolicyType(option)" @click="setPolicyType(option)"
......
query scanResultPolicies($fullPath: ID!) {
project(fullPath: $fullPath) {
id
scanResultPolicies {
nodes {
name
yaml
enabled
updatedAt
}
}
}
}
...@@ -25,6 +25,9 @@ export const getPolicyType = (typeName = '') => { ...@@ -25,6 +25,9 @@ export const getPolicyType = (typeName = '') => {
if (typeName === POLICY_TYPE_COMPONENT_OPTIONS.scanExecution.typeName) { if (typeName === POLICY_TYPE_COMPONENT_OPTIONS.scanExecution.typeName) {
return POLICY_TYPE_COMPONENT_OPTIONS.scanExecution.value; return POLICY_TYPE_COMPONENT_OPTIONS.scanExecution.value;
} }
if (typeName === POLICY_TYPE_COMPONENT_OPTIONS.scanResult.typeName) {
return POLICY_TYPE_COMPONENT_OPTIONS.scanResult.value;
}
return null; return null;
}; };
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
= f.label :setup_for_company, setup_for_company_label_text, class: 'label-bold' = f.label :setup_for_company, setup_for_company_label_text, class: 'label-bold'
.gl-display-flex.gl-flex-direction-column.gl-lg-flex-direction-row .gl-display-flex.gl-flex-direction-column.gl-lg-flex-direction-row
.gl-flex-grow-1 .gl-flex-grow-1
= f.radio_button :setup_for_company, true, class: 'js-setup-for-company', required: true = f.radio_button :setup_for_company, true, class: 'js-setup-for-company', required: true, data: { qa_selector: 'setup_for_company_radio' }
= f.label :setup_for_company, _('My company or team'), class: 'normal', value: 'true' = f.label :setup_for_company, _('My company or team'), class: 'normal', value: 'true'
.gl-flex-grow-1 .gl-flex-grow-1
= f.radio_button :setup_for_company, false, class: 'js-setup-for-me', required: true = f.radio_button :setup_for_company, false, class: 'js-setup-for-me', required: true
......
...@@ -8,15 +8,21 @@ import PolicyDrawer from 'ee/threat_monitoring/components/policy_drawer/policy_d ...@@ -8,15 +8,21 @@ import PolicyDrawer from 'ee/threat_monitoring/components/policy_drawer/policy_d
import { PREDEFINED_NETWORK_POLICIES } from 'ee/threat_monitoring/constants'; import { PREDEFINED_NETWORK_POLICIES } from 'ee/threat_monitoring/constants';
import networkPoliciesQuery from 'ee/threat_monitoring/graphql/queries/network_policies.query.graphql'; import networkPoliciesQuery from 'ee/threat_monitoring/graphql/queries/network_policies.query.graphql';
import scanExecutionPoliciesQuery from 'ee/threat_monitoring/graphql/queries/scan_execution_policies.query.graphql'; import scanExecutionPoliciesQuery from 'ee/threat_monitoring/graphql/queries/scan_execution_policies.query.graphql';
import scanResultPoliciesQuery from 'ee/threat_monitoring/graphql/queries/scan_result_policies.query.graphql';
import createStore from 'ee/threat_monitoring/store'; import createStore from 'ee/threat_monitoring/store';
import createMockApollo from 'helpers/mock_apollo_helper'; import createMockApollo from 'helpers/mock_apollo_helper';
import { stubComponent } from 'helpers/stub_component'; import { stubComponent } from 'helpers/stub_component';
import { mountExtended, shallowMountExtended } from 'helpers/vue_test_utils_helper'; import { mountExtended, shallowMountExtended } from 'helpers/vue_test_utils_helper';
import waitForPromises from 'helpers/wait_for_promises'; import waitForPromises from 'helpers/wait_for_promises';
import { networkPolicies, scanExecutionPolicies } from '../../mocks/mock_apollo'; import {
networkPolicies,
scanExecutionPolicies,
scanResultPolicies,
} from '../../mocks/mock_apollo';
import { import {
mockNetworkPoliciesResponse, mockNetworkPoliciesResponse,
mockScanExecutionPoliciesResponse, mockScanExecutionPoliciesResponse,
mockScanResultPoliciesResponse,
} from '../../mocks/mock_data'; } from '../../mocks/mock_data';
const localVue = createLocalVue(); const localVue = createLocalVue();
...@@ -35,9 +41,11 @@ const environments = [ ...@@ -35,9 +41,11 @@ const environments = [
]; ];
const networkPoliciesSpy = networkPolicies(mockNetworkPoliciesResponse); const networkPoliciesSpy = networkPolicies(mockNetworkPoliciesResponse);
const scanExecutionPoliciesSpy = scanExecutionPolicies(mockScanExecutionPoliciesResponse); const scanExecutionPoliciesSpy = scanExecutionPolicies(mockScanExecutionPoliciesResponse);
const scanResultPoliciesSpy = scanResultPolicies(mockScanResultPoliciesResponse);
const defaultRequestHandlers = { const defaultRequestHandlers = {
networkPolicies: networkPoliciesSpy, networkPolicies: networkPoliciesSpy,
scanExecutionPolicies: scanExecutionPoliciesSpy, scanExecutionPolicies: scanExecutionPoliciesSpy,
scanResultPolicies: scanResultPoliciesSpy,
}; };
const pendingHandler = jest.fn(() => new Promise(() => {})); const pendingHandler = jest.fn(() => new Promise(() => {}));
...@@ -81,10 +89,12 @@ describe('PoliciesList component', () => { ...@@ -81,10 +89,12 @@ describe('PoliciesList component', () => {
documentationPath: 'path/to/docs', documentationPath: 'path/to/docs',
newPolicyPath: 'path/to/policy', newPolicyPath: 'path/to/policy',
projectPath: fullPath, projectPath: fullPath,
glFeatures: { scanResultPolicy: true },
}, },
apolloProvider: createMockApollo([ apolloProvider: createMockApollo([
[networkPoliciesQuery, requestHandlers.networkPolicies], [networkPoliciesQuery, requestHandlers.networkPolicies],
[scanExecutionPoliciesQuery, requestHandlers.scanExecutionPolicies], [scanExecutionPoliciesQuery, requestHandlers.scanExecutionPolicies],
[scanResultPoliciesQuery, requestHandlers.scanResultPolicies],
]), ]),
stubs: { stubs: {
PolicyDrawer: stubComponent(PolicyDrawer, { PolicyDrawer: stubComponent(PolicyDrawer, {
...@@ -163,7 +173,7 @@ describe('PoliciesList component', () => { ...@@ -163,7 +173,7 @@ describe('PoliciesList component', () => {
}); });
it('does render default network policies', () => { it('does render default network policies', () => {
expect(findPolicyStatusCells()).toHaveLength(5); expect(findPolicyStatusCells()).toHaveLength(6);
}); });
it('fetches network policies on environment change', async () => { it('fetches network policies on environment change', async () => {
...@@ -190,9 +200,10 @@ describe('PoliciesList component', () => { ...@@ -190,9 +200,10 @@ describe('PoliciesList component', () => {
describe.each` describe.each`
rowIndex | expectedPolicyName | expectedPolicyType rowIndex | expectedPolicyName | expectedPolicyType
${1} | ${mockScanExecutionPoliciesResponse[0].name} | ${'Scan execution'} ${1} | ${mockScanExecutionPoliciesResponse[0].name} | ${'Scan execution'}
${3} | ${mockNetworkPoliciesResponse[0].name} | ${'Network'} ${2} | ${mockScanResultPoliciesResponse[0].name} | ${'Scan result'}
${4} | ${PREDEFINED_NETWORK_POLICIES[0].name} | ${'Network'} ${3} | ${mockNetworkPoliciesResponse[1].name} | ${'Network'}
${5} | ${PREDEFINED_NETWORK_POLICIES[1].name} | ${'Network'} ${4} | ${mockNetworkPoliciesResponse[0].name} | ${'Network'}
${5} | ${PREDEFINED_NETWORK_POLICIES[0].name} | ${'Network'}
`('policy in row #$rowIndex', ({ rowIndex, expectedPolicyName, expectedPolicyType }) => { `('policy in row #$rowIndex', ({ rowIndex, expectedPolicyName, expectedPolicyType }) => {
let row; let row;
...@@ -211,8 +222,9 @@ describe('PoliciesList component', () => { ...@@ -211,8 +222,9 @@ describe('PoliciesList component', () => {
it.each` it.each`
description | filterBy | hiddenTypes description | filterBy | hiddenTypes
${'network'} | ${POLICY_TYPE_OPTIONS.POLICY_TYPE_NETWORK} | ${[POLICY_TYPE_OPTIONS.POLICY_TYPE_SCAN_EXECUTION]} ${'network'} | ${POLICY_TYPE_OPTIONS.POLICY_TYPE_NETWORK} | ${[POLICY_TYPE_OPTIONS.POLICY_TYPE_SCAN_EXECUTION, POLICY_TYPE_OPTIONS.POLICY_TYPE_SCAN_RESULT]}
${'scan execution'} | ${POLICY_TYPE_OPTIONS.POLICY_TYPE_SCAN_EXECUTION} | ${[POLICY_TYPE_OPTIONS.POLICY_TYPE_NETWORK]} ${'scan execution'} | ${POLICY_TYPE_OPTIONS.POLICY_TYPE_SCAN_EXECUTION} | ${[POLICY_TYPE_OPTIONS.POLICY_TYPE_NETWORK, POLICY_TYPE_OPTIONS.POLICY_TYPE_SCAN_RESULT]}
${'scan result'} | ${POLICY_TYPE_OPTIONS.POLICY_TYPE_SCAN_RESULT} | ${[POLICY_TYPE_OPTIONS.POLICY_TYPE_NETWORK, POLICY_TYPE_OPTIONS.POLICY_TYPE_SCAN_EXECUTION]}
`('policies filtered by $description type', async ({ filterBy, hiddenTypes }) => { `('policies filtered by $description type', async ({ filterBy, hiddenTypes }) => {
findPolicyTypeFilter().vm.$emit('input', filterBy.value); findPolicyTypeFilter().vm.$emit('input', filterBy.value);
await wrapper.vm.$nextTick(); await wrapper.vm.$nextTick();
...@@ -258,7 +270,7 @@ describe('PoliciesList component', () => { ...@@ -258,7 +270,7 @@ describe('PoliciesList component', () => {
}); });
it('renders a "Disabled" label for screen readers for disabled policies', () => { it('renders a "Disabled" label for screen readers for disabled policies', () => {
const span = findPolicyStatusCells().at(3).find('span'); const span = findPolicyStatusCells().at(4).find('span');
expect(span.exists()).toBe(true); expect(span.exists()).toBe(true);
expect(span.attributes('class')).toBe('gl-sr-only'); expect(span.attributes('class')).toBe('gl-sr-only');
...@@ -284,6 +296,7 @@ describe('PoliciesList component', () => { ...@@ -284,6 +296,7 @@ describe('PoliciesList component', () => {
${PREDEFINED_NETWORK_POLICIES[0].name} | ${PREDEFINED_NETWORK_POLICIES[0]} | ${'container'} | ${'path/to/policy?environment_id=2&type=container_policy&kind=CiliumNetworkPolicy'} ${PREDEFINED_NETWORK_POLICIES[0].name} | ${PREDEFINED_NETWORK_POLICIES[0]} | ${'container'} | ${'path/to/policy?environment_id=2&type=container_policy&kind=CiliumNetworkPolicy'}
${PREDEFINED_NETWORK_POLICIES[1].name} | ${PREDEFINED_NETWORK_POLICIES[1]} | ${'container'} | ${'path/to/policy?environment_id=2&type=container_policy&kind=CiliumNetworkPolicy'} ${PREDEFINED_NETWORK_POLICIES[1].name} | ${PREDEFINED_NETWORK_POLICIES[1]} | ${'container'} | ${'path/to/policy?environment_id=2&type=container_policy&kind=CiliumNetworkPolicy'}
${'scan execution'} | ${mockScanExecutionPoliciesResponse[0]} | ${'scanExecution'} | ${'path/to/policy?environment_id=2&type=scan_execution_policy'} ${'scan execution'} | ${mockScanExecutionPoliciesResponse[0]} | ${'scanExecution'} | ${'path/to/policy?environment_id=2&type=scan_execution_policy'}
${'scan result'} | ${mockScanResultPoliciesResponse[0]} | ${'scanResult'} | ${'path/to/policy?environment_id=2&type=scan_result_policy'}
`('given there is a $description policy selected', ({ policy, policyType, editPolicyPath }) => { `('given there is a $description policy selected', ({ policy, policyType, editPolicyPath }) => {
beforeEach(() => { beforeEach(() => {
mountShallowWrapper(); mountShallowWrapper();
...@@ -331,7 +344,7 @@ describe('PoliciesList component', () => { ...@@ -331,7 +344,7 @@ describe('PoliciesList component', () => {
}); });
it('does not render default network policies', () => { it('does not render default network policies', () => {
expect(findPolicyStatusCells()).toHaveLength(1); expect(findPolicyStatusCells()).toHaveLength(2);
}); });
}); });
}); });
...@@ -57,6 +57,18 @@ export const scanExecutionPolicies = (nodes) => ...@@ -57,6 +57,18 @@ export const scanExecutionPolicies = (nodes) =>
}, },
}); });
export const scanResultPolicies = (nodes) =>
jest.fn().mockResolvedValue({
data: {
project: {
id: '3',
scanResultPolicies: {
nodes,
},
},
},
});
export const mockLinkSecurityPolicyProjectResponses = { export const mockLinkSecurityPolicyProjectResponses = {
success: jest.fn().mockResolvedValue({ data: { securityPolicyProjectAssign: { errors: [] } } }), success: jest.fn().mockResolvedValue({ data: { securityPolicyProjectAssign: { errors: [] } } }),
failure: jest failure: jest
......
...@@ -200,8 +200,40 @@ export const mockScanExecutionPolicy = { ...@@ -200,8 +200,40 @@ export const mockScanExecutionPolicy = {
latestScan: { date: new Date('2021-06-07T00:00:00.000Z'), pipelineUrl: 'path/to/pipeline' }, latestScan: { date: new Date('2021-06-07T00:00:00.000Z'), pipelineUrl: 'path/to/pipeline' },
}; };
export const mockScanResultManifest = `type: scan_execution_policy
name: critical vulnerability CS approvals
description: This policy enforces critical vulnerability CS approvals
enabled: true
rules:
- type: scan_finding
branches:
- master
scanners:
- container_scanning
vulnerability_allowed: 1
severity_levels:
- critical
vulnerability_states:
- newly_added
actions:
- type: require_approval
approvals_required: 1
user_approvers:
- the.one
`;
export const mockScanResultPolicy = {
__typename: 'ScanResultPolicy',
name: 'critical vulnerability CS approvals',
updatedAt: new Date('2021-06-07T00:00:00.000Z'),
yaml: mockScanResultManifest,
enabled: true,
};
export const mockScanExecutionPoliciesResponse = [mockScanExecutionPolicy]; export const mockScanExecutionPoliciesResponse = [mockScanExecutionPolicy];
export const mockScanResultPoliciesResponse = [mockScanResultPolicy];
export const mockNominalHistory = [ export const mockNominalHistory = [
['2019-12-04T00:00:00.000Z', 56], ['2019-12-04T00:00:00.000Z', 56],
['2019-12-05T00:00:00.000Z', 2647], ['2019-12-05T00:00:00.000Z', 2647],
......
...@@ -31642,12 +31642,18 @@ msgstr "" ...@@ -31642,12 +31642,18 @@ msgstr ""
msgid "SecurityOrchestration|Scan Execution" msgid "SecurityOrchestration|Scan Execution"
msgstr "" msgstr ""
msgid "SecurityOrchestration|Scan Result"
msgstr ""
msgid "SecurityOrchestration|Scan execution" msgid "SecurityOrchestration|Scan execution"
msgstr "" msgstr ""
msgid "SecurityOrchestration|Scan execution policies can only be created by project owners." msgid "SecurityOrchestration|Scan execution policies can only be created by project owners."
msgstr "" msgstr ""
msgid "SecurityOrchestration|Scan result"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed %{cadence}" msgid "SecurityOrchestration|Scan to be performed %{cadence}"
msgstr "" msgstr ""
......
# frozen_string_literal: true
module Gitlab
module Page
module Main
class Welcome < Chemlab::Page
path '/users/sign_up/welcome'
button :get_started_button
end
end
end
end
# frozen_string_literal: true
module Gitlab
module Page
module Main
module Welcome
# @note Defined as +button :get_started_button+
# Clicks +get_started_button+
def get_started_button
# This is a stub, used for indexing. The method is dynamically generated.
end
# @example
# Gitlab::Page::Main::Welcome.perform do |welcome|
# expect(welcome.get_started_button_element).to exist
# end
# @return [Watir::Button] The raw +Button+ element
def get_started_button_element
# This is a stub, used for indexing. The method is dynamically generated.
end
# @example
# Gitlab::Page::Main::Welcome.perform do |welcome|
# expect(welcome).to be_get_started_button
# end
# @return [Boolean] true if the +get_started_button+ element is present on the page
def get_started_button?
# This is a stub, used for indexing. The method is dynamically generated.
end
end
end
end
end
...@@ -7,13 +7,24 @@ module QA ...@@ -7,13 +7,24 @@ module QA
module Welcome module Welcome
extend QA::Page::PageConcern extend QA::Page::PageConcern
def self.included(base) def self.prepended(base)
super super
base.view 'ee/app/views/registrations/welcome/_button.html.haml' do base.class_eval do
element :get_started_button view 'ee/app/views/registrations/welcome/_button.html.haml' do
element :get_started_button
end
view 'ee/app/views/registrations/welcome/_setup_for_company.html.haml' do
element :setup_for_company_radio
end
end end
end end
# setup_for_company_radio is only shown in development environment and .com
def choose_setup_for_company_if_available
choose_element(:setup_for_company_radio) if QA::Runtime::Env.running_on_dev_or_dot_com?
end
end end
end end
end end
......
...@@ -26,9 +26,12 @@ module QA ...@@ -26,9 +26,12 @@ module QA
sign_up.click_new_user_register_button sign_up.click_new_user_register_button
end end
Page::Registration::Welcome.perform(&:click_get_started_button_if_available) Flow::UserOnboarding.onboard_user
success = if user.expect_fabrication_success success = if user.expect_fabrication_success
# In development env and .com the user is asked to create a group and a project which can be skipped for
# the purpose of signing up
Runtime::Browser.visit(:gitlab, Page::Dashboard::Welcome)
Page::Main::Menu.perform(&:has_personal_area?) Page::Main::Menu.perform(&:has_personal_area?)
else else
Page::Main::Menu.perform(&:not_signed_in?) Page::Main::Menu.perform(&:not_signed_in?)
......
# frozen_string_literal: true
module QA
module Flow
module UserOnboarding
module_function
def onboard_user
Page::Registration::Welcome.perform do |welcome_page|
if welcome_page.has_get_started_button?
welcome_page.select_role('Other')
welcome_page.choose_setup_for_company_if_available
welcome_page.click_get_started_button
end
end
end
end
end
end
...@@ -11,6 +11,10 @@ module QA ...@@ -11,6 +11,10 @@ module QA
def has_welcome_title?(text) def has_welcome_title?(text)
has_element?(:welcome_title_content, text: text) has_element?(:welcome_title_content, text: text)
end end
def self.path
'/'
end
end end
end end
end end
......
...@@ -16,10 +16,6 @@ module QA ...@@ -16,10 +16,6 @@ module QA
element :new_user_username_field element :new_user_username_field
end end
view 'app/views/registrations/welcome/show.html.haml' do
element :get_started_button
end
def fill_new_user_first_name_field(first_name) def fill_new_user_first_name_field(first_name)
fill_element :new_user_first_name_field, first_name fill_element :new_user_first_name_field, first_name
end end
......
...@@ -6,14 +6,25 @@ module QA ...@@ -6,14 +6,25 @@ module QA
class Welcome < Page::Base class Welcome < Page::Base
view 'app/views/registrations/welcome/show.html.haml' do view 'app/views/registrations/welcome/show.html.haml' do
element :get_started_button element :get_started_button
element :role_dropdown
end end
def click_get_started_button_if_available def has_get_started_button?
if has_element?(:get_started_button) has_element?(:get_started_button)
Support::Retrier.retry_until do end
click_element :get_started_button
has_no_element?(:get_started_button) def select_role(role)
end select_element(:role_dropdown, role)
end
def choose_setup_for_company_if_available
# Only implemented in EE
end
def click_get_started_button
Support::Retrier.retry_until do
click_element :get_started_button
has_no_element?(:get_started_button)
end end
end end
end end
......
...@@ -90,6 +90,20 @@ module QA ...@@ -90,6 +90,20 @@ module QA
enabled?(ENV['ACCEPT_INSECURE_CERTS']) enabled?(ENV['ACCEPT_INSECURE_CERTS'])
end end
def running_on_dot_com?
uri = URI.parse(Runtime::Scenario.gitlab_address)
uri.host.include?('.com')
end
def running_on_dev?
uri = URI.parse(Runtime::Scenario.gitlab_address)
uri.port != 80 && uri.port != 443
end
def running_on_dev_or_dot_com?
running_on_dev? || running_on_dot_com?
end
def running_in_ci? def running_in_ci?
ENV['CI'] || ENV['CI_SERVER'] ENV['CI'] || ENV['CI_SERVER']
end end
......
...@@ -118,11 +118,12 @@ module QA ...@@ -118,11 +118,12 @@ module QA
Flow::Login.sign_in(as: @user, skip_page_validation: true) Flow::Login.sign_in(as: @user, skip_page_validation: true)
Page::Registration::Welcome.perform(&:click_get_started_button_if_available) Flow::UserOnboarding.onboard_user
Page::Main::Menu.perform do |menu| # In development env and .com the user is asked to create a group and a project which can be skipped for
expect(menu).to have_personal_area # the purpose of this test
end Runtime::Browser.visit(:gitlab, Page::Dashboard::Welcome)
Page::Main::Menu.perform(&:has_personal_area?)
end end
after do after do
......
...@@ -20,6 +20,7 @@ module QA ...@@ -20,6 +20,7 @@ module QA
before do before do
# Enable sign-ups # Enable sign-ups
Runtime::ApplicationSettings.set_application_settings(signup_enabled: true) Runtime::ApplicationSettings.set_application_settings(signup_enabled: true)
Runtime::ApplicationSettings.set_application_settings(require_admin_approval_after_user_signup: true)
# Register the new user through the registration page # Register the new user through the registration page
Gitlab::Page::Main::SignUp.perform do |sign_up| Gitlab::Page::Main::SignUp.perform do |sign_up|
...@@ -27,10 +28,7 @@ module QA ...@@ -27,10 +28,7 @@ module QA
sign_up.register_user(user) sign_up.register_user(user)
end end
# Click the Get Started button on the welcome page if it presents itself Flow::UserOnboarding.onboard_user
Gitlab::Page::Main::Welcome.perform do |welcome|
welcome.get_started_button if welcome.get_started_button?
end
end end
after do after do
......
...@@ -83,6 +83,46 @@ RSpec.describe QA::Runtime::Env do ...@@ -83,6 +83,46 @@ RSpec.describe QA::Runtime::Env do
end end
end end
describe '.running_on_dot_com?' do
using RSpec::Parameterized::TableSyntax
where(:url, :result) do
'https://www.gitlab.com' | true
'https://staging.gitlab.com' | true
'http://www.gitlab.com' | true
'http://localhost:3000' | false
'http://localhost' | false
'http://gdk.test:3000' | false
end
with_them do
before do
QA::Runtime::Scenario.define(:gitlab_address, url)
end
it { expect(described_class.running_on_dot_com?).to eq result }
end
end
describe '.running_on_dev?' do
using RSpec::Parameterized::TableSyntax
where(:url, :result) do
'https://www.gitlab.com' | false
'http://localhost:3000' | true
'http://localhost' | false
'http://gdk.test:3000' | true
end
with_them do
before do
QA::Runtime::Scenario.define(:gitlab_address, url)
end
it { expect(described_class.running_on_dev?).to eq result }
end
end
describe '.personal_access_token' do describe '.personal_access_token' do
around do |example| around do |example|
described_class.instance_variable_set(:@personal_access_token, nil) described_class.instance_variable_set(:@personal_access_token, nil)
......
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