Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
9dee2023
Commit
9dee2023
authored
Aug 12, 2021
by
Zamir Martins
Committed by
Jose Ivan Vargas
Aug 12, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add severity_levels in UI dialogs related to project approval rules
parent
86abff01
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
174 additions
and
27 deletions
+174
-27
ee/app/assets/javascripts/approvals/components/rule_form.vue
ee/app/assets/javascripts/approvals/components/rule_form.vue
+96
-18
ee/app/assets/javascripts/approvals/constants.js
ee/app/assets/javascripts/approvals/constants.js
+9
-2
ee/app/assets/javascripts/approvals/mappers.js
ee/app/assets/javascripts/approvals/mappers.js
+2
-0
ee/spec/frontend/approvals/components/rule_form_spec.js
ee/spec/frontend/approvals/components/rule_form_spec.js
+51
-6
locale/gitlab.pot
locale/gitlab.pot
+16
-1
No files found.
ee/app/assets/javascripts/approvals/components/rule_form.vue
View file @
9dee2023
...
...
@@ -2,7 +2,7 @@
import
{
GlFormGroup
,
GlFormInput
,
GlDropdown
,
GlTruncate
,
GlDropdownItem
}
from
'
@gitlab/ui
'
;
import
{
groupBy
,
isEqual
,
isNumber
,
omit
}
from
'
lodash
'
;
import
{
mapState
,
mapActions
}
from
'
vuex
'
;
import
{
REPORT_TYPES
}
from
'
ee/security_dashboard/store/constants
'
;
import
{
REPORT_TYPES
,
SEVERITY_LEVELS
}
from
'
ee/security_dashboard/store/constants
'
;
import
ProtectedBranchesSelector
from
'
ee/vue_shared/components/branches_selector/protected_branches_selector.vue
'
;
import
{
sprintf
}
from
'
~/locale
'
;
import
{
...
...
@@ -71,6 +71,7 @@ export default {
containsHiddenGroups
:
false
,
serverValidationErrors
:
[],
scanners
:
[],
severityLevels
:
[],
...
this
.
getInitialData
(),
};
},
...
...
@@ -98,11 +99,11 @@ export default {
invalidName
()
{
if
(
this
.
isMultiSubmission
)
{
if
(
this
.
serverValidationErrors
.
includes
(
'
name has already been taken
'
))
{
return
this
.
$options
.
APPROVAL_DIALOG_I18N
.
validations
.
ruleNameTaken
;
return
APPROVAL_DIALOG_I18N
.
validations
.
ruleNameTaken
;
}
if
(
!
this
.
name
)
{
return
this
.
$options
.
APPROVAL_DIALOG_I18N
.
validations
.
ruleNameMissing
;
return
APPROVAL_DIALOG_I18N
.
validations
.
ruleNameMissing
;
}
}
...
...
@@ -110,15 +111,15 @@ export default {
},
invalidApprovalsRequired
()
{
if
(
!
isNumber
(
this
.
approvalsRequired
))
{
return
this
.
$options
.
APPROVAL_DIALOG_I18N
.
validations
.
approvalsRequiredNotNumber
;
return
APPROVAL_DIALOG_I18N
.
validations
.
approvalsRequiredNotNumber
;
}
if
(
this
.
approvalsRequired
<
0
)
{
return
this
.
$options
.
APPROVAL_DIALOG_I18N
.
validations
.
approvalsRequiredNegativeNumber
;
return
APPROVAL_DIALOG_I18N
.
validations
.
approvalsRequiredNegativeNumber
;
}
if
(
this
.
approvalsRequired
<
this
.
minApprovalsRequired
)
{
return
sprintf
(
this
.
$options
.
APPROVAL_DIALOG_I18N
.
validations
.
approvalsRequiredMinimum
,
{
return
sprintf
(
APPROVAL_DIALOG_I18N
.
validations
.
approvalsRequiredMinimum
,
{
number
:
this
.
minApprovalsRequired
,
});
}
...
...
@@ -127,7 +128,7 @@ export default {
},
invalidApprovers
()
{
if
(
this
.
isMultiSubmission
&&
this
.
approvers
.
length
<=
0
)
{
return
this
.
$options
.
APPROVAL_DIALOG_I18N
.
validations
.
approversRequired
;
return
APPROVAL_DIALOG_I18N
.
validations
.
approversRequired
;
}
return
''
;
...
...
@@ -137,25 +138,33 @@ export default {
!
this
.
isMrEdit
&&
!
this
.
branches
.
every
((
branch
)
=>
isEqual
(
branch
,
ANY_BRANCH
)
||
isNumber
(
branch
?.
id
))
)
{
return
this
.
$options
.
APPROVAL_DIALOG_I18N
.
validations
.
branchesRequired
;
return
APPROVAL_DIALOG_I18N
.
validations
.
branchesRequired
;
}
return
''
;
},
invalidScanners
()
{
if
(
this
.
scanners
.
length
<=
0
)
{
return
this
.
$options
.
APPROVAL_DIALOG_I18N
.
validations
.
scannersRequired
;
return
APPROVAL_DIALOG_I18N
.
validations
.
scannersRequired
;
}
return
''
;
},
invalidVulnerabilitiesAllowedError
()
{
if
(
!
isNumber
(
this
.
vulnerabilitiesAllowed
))
{
return
this
.
$options
.
APPROVAL_DIALOG_I18N
.
validations
.
approvalsRequiredNotNumber
;
return
APPROVAL_DIALOG_I18N
.
validations
.
approvalsRequiredNotNumber
;
}
if
(
this
.
vulnerabilitiesAllowed
<
0
)
{
return
this
.
$options
.
APPROVAL_DIALOG_I18N
.
validations
.
vulnerabilitiesAllowedMinimum
;
return
APPROVAL_DIALOG_I18N
.
validations
.
vulnerabilitiesAllowedMinimum
;
}
return
''
;
},
invalidSeverityLevels
()
{
if
(
this
.
severityLevels
.
length
===
0
)
{
return
APPROVAL_DIALOG_I18N
.
validations
.
severityLevelsRequired
;
}
return
''
;
},
isValid
()
{
...
...
@@ -165,7 +174,8 @@ export default {
this
.
isValidApprovalsRequired
&&
this
.
isValidApprovers
&&
this
.
areValidScanners
&&
this
.
isValidVulnerabilitiesAllowed
this
.
isValidVulnerabilitiesAllowed
&&
this
.
areValidSeverityLevels
);
},
isValidName
()
{
...
...
@@ -190,6 +200,9 @@ export default {
!
this
.
invalidVulnerabilitiesAllowedError
);
},
areValidSeverityLevels
()
{
return
!
this
.
showValidation
||
!
this
.
isVulnerabilityCheck
||
!
this
.
invalidSeverityLevels
;
},
isMultiSubmission
()
{
return
this
.
settings
.
allowMultiRule
&&
!
this
.
isFallbackSubmission
;
},
...
...
@@ -228,6 +241,7 @@ export default {
removeHiddenGroups
:
this
.
removeHiddenGroups
,
protectedBranchIds
:
this
.
branches
.
map
((
x
)
=>
x
.
id
),
scanners
:
this
.
scanners
,
severityLevels
:
this
.
severityLevels
,
};
},
isEditing
()
{
...
...
@@ -242,15 +256,33 @@ export default {
scannersText
()
{
switch
(
this
.
scanners
.
length
)
{
case
Object
.
values
(
this
.
$options
.
REPORT_TYPES
).
length
:
return
this
.
$options
.
APPROVAL_DIALOG_I18N
.
form
.
allScannersSelectedLabel
;
return
APPROVAL_DIALOG_I18N
.
form
.
allScannersSelectedLabel
;
case
0
:
return
this
.
$options
.
APPROVAL_DIALOG_I18N
.
form
.
scannersSelectLabel
;
return
APPROVAL_DIALOG_I18N
.
form
.
scannersSelectLabel
;
case
1
:
return
this
.
$options
.
REPORT_TYPES
[
this
.
scanners
[
0
]];
default
:
return
sprintf
(
this
.
$options
.
APPROVAL_DIALOG_I18N
.
form
.
multipleSelectedScannersLabel
,
{
scanner
:
this
.
$options
.
REPORT_TYPES
[
this
.
scanners
[
0
]],
additionalScanners
:
this
.
scanners
.
length
-
1
,
return
sprintf
(
APPROVAL_DIALOG_I18N
.
form
.
multipleSelectedLabel
,
{
firstLabel
:
this
.
$options
.
REPORT_TYPES
[
this
.
scanners
[
0
]],
numberOfAdditionalLabels
:
this
.
scanners
.
length
-
1
,
});
}
},
areAllSeverityLevelsSelected
()
{
return
this
.
severityLevels
.
length
===
Object
.
values
(
this
.
$options
.
SEVERITY_LEVELS
).
length
;
},
severityLevelsText
()
{
switch
(
this
.
severityLevels
.
length
)
{
case
Object
.
keys
(
this
.
$options
.
SEVERITY_LEVELS
).
length
:
return
APPROVAL_DIALOG_I18N
.
form
.
allSeverityLevelsSelectedLabel
;
case
0
:
return
APPROVAL_DIALOG_I18N
.
form
.
severityLevelsSelectLabel
;
case
1
:
return
this
.
$options
.
SEVERITY_LEVELS
[
this
.
severityLevels
[
0
]];
default
:
return
sprintf
(
APPROVAL_DIALOG_I18N
.
form
.
multipleSelectedLabel
,
{
firstLabel
:
this
.
$options
.
SEVERITY_LEVELS
[
this
.
severityLevels
[
0
]],
numberOfAdditionalLabels
:
this
.
severityLevels
.
length
-
1
,
});
}
},
...
...
@@ -371,6 +403,7 @@ export default {
branches
,
scanners
:
this
.
initRule
.
scanners
||
[],
vulnerabilitiesAllowed
:
this
.
initRule
.
vulnerabilitiesAllowed
||
0
,
severityLevels
:
this
.
initRule
.
severityLevels
||
[],
};
},
setAllSelectedScanners
()
{
...
...
@@ -387,9 +420,26 @@ export default {
this
.
scanners
.
splice
(
pos
,
1
);
}
},
setAllSelectedSeverityLevels
()
{
this
.
severityLevels
=
this
.
areAllSeverityLevelsSelected
?
[]
:
Object
.
keys
(
this
.
$options
.
SEVERITY_LEVELS
);
},
isSeveritySelected
(
severity
)
{
return
this
.
severityLevels
.
includes
(
severity
);
},
setSeverity
(
severity
)
{
const
pos
=
this
.
severityLevels
.
indexOf
(
severity
);
if
(
pos
===
-
1
)
{
this
.
severityLevels
.
push
(
severity
);
}
else
{
this
.
severityLevels
.
splice
(
pos
,
1
);
}
},
},
APPROVAL_DIALOG_I18N
,
REPORT_TYPES
:
omit
(
REPORT_TYPES
,
EXCLUDED_REPORT_TYPE
),
SEVERITY_LEVELS
,
};
</
script
>
...
...
@@ -441,7 +491,7 @@ export default {
:is-checked=
"areAllScannersSelected"
@
click.native.capture.stop=
"setAllSelectedScanners"
>
<gl-truncate
:text=
"$options.APPROVAL_DIALOG_I18N.form.selectAll
Scanners
Label"
/>
<gl-truncate
:text=
"$options.APPROVAL_DIALOG_I18N.form.selectAllLabel"
/>
</gl-dropdown-item>
<gl-dropdown-item
v-for=
"(value, key) in $options.REPORT_TYPES"
...
...
@@ -454,6 +504,34 @@ export default {
</gl-dropdown-item>
</gl-dropdown>
</gl-form-group>
<gl-form-group
v-if=
"isVulnerabilityCheck"
:label=
"$options.APPROVAL_DIALOG_I18N.form.severityLevelsLabel"
:description=
"$options.APPROVAL_DIALOG_I18N.form.severityLevelsDescription"
:state=
"areValidSeverityLevels"
:invalid-feedback=
"invalidSeverityLevels"
data-testid=
"severity-levels-group"
>
<gl-dropdown
:text=
"severityLevelsText"
>
<gl-dropdown-item
key=
"all"
is-check-item
:is-checked=
"areAllSeverityLevelsSelected"
@
click.native.capture.stop=
"setAllSelectedSeverityLevels"
>
<gl-truncate
:text=
"$options.APPROVAL_DIALOG_I18N.form.selectAllLabel"
/>
</gl-dropdown-item>
<gl-dropdown-item
v-for=
"(value, key) in $options.SEVERITY_LEVELS"
:key=
"key"
is-check-item
:is-checked=
"isSeveritySelected(key)"
@
click.native.capture.stop=
"setSeverity(key)"
>
<gl-truncate
:text=
"value"
/>
</gl-dropdown-item>
</gl-dropdown>
</gl-form-group>
<gl-form-group
:label=
"$options.APPROVAL_DIALOG_I18N.form.approvalsRequiredLabel"
:state=
"isValidApprovalsRequired"
...
...
ee/app/assets/javascripts/approvals/constants.js
View file @
9dee2023
...
...
@@ -90,13 +90,19 @@ export const APPROVAL_DIALOG_I18N = {
scannersDescription
:
s__
(
'
ApprovalRule|Apply this approval rule to consider only the selected security scanners.
'
,
),
selectAll
Scanners
Label
:
s__
(
'
ApprovalRule|Select All
'
),
selectAllLabel
:
s__
(
'
ApprovalRule|Select All
'
),
allScannersSelectedLabel
:
s__
(
'
ApprovalRule|All scanners
'
),
multipleSelected
ScannersLabel
:
s__
(
'
ApprovalRule|%{scanner} +%{additionalScanner
s} more
'
),
multipleSelected
Label
:
s__
(
'
ApprovalRule|%{firstLabel} +%{numberOfAdditionalLabel
s} more
'
),
vulnerabilitiesAllowedLabel
:
s__
(
'
ApprovalRule|Vulnerabilities allowed
'
),
vulnerabilitiesAllowedDescription
:
s__
(
'
ApprovalRule|Number of vulnerabilities allowed before approval rule is triggered.
'
,
),
severityLevelsLabel
:
s__
(
'
ApprovalRule|Severity levels
'
),
severityLevelsDescription
:
s__
(
'
ApprovalRule|Apply this approval rule to consider only the selected severity levels.
'
,
),
severityLevelsSelectLabel
:
s__
(
'
ApprovalRule|Select severity levels
'
),
allSeverityLevelsSelectedLabel
:
s__
(
'
ApprovalRule|All severity levels
'
),
},
validations
:
{
approvalsRequiredNegativeNumber
:
__
(
'
Please enter a non-negative number
'
),
...
...
@@ -112,5 +118,6 @@ export const APPROVAL_DIALOG_I18N = {
vulnerabilitiesAllowedMinimum
:
s__
(
'
ApprovalRule|Please enter a number equal or greater than zero
'
,
),
severityLevelsRequired
:
s__
(
'
ApprovalRule|Please select at least one severity level
'
),
},
};
ee/app/assets/javascripts/approvals/mappers.js
View file @
9dee2023
...
...
@@ -33,6 +33,7 @@ export const mapApprovalRuleRequest = (req) => ({
protected_branch_ids
:
req
.
protectedBranchIds
,
scanners
:
req
.
scanners
,
vulnerabilities_allowed
:
req
.
vulnerabilitiesAllowed
,
severity_levels
:
req
.
severityLevels
,
});
export
const
mapApprovalFallbackRuleRequest
=
(
req
)
=>
({
...
...
@@ -54,6 +55,7 @@ export const mapApprovalRuleResponse = (res) => ({
overridden
:
res
.
overridden
,
scanners
:
res
.
scanners
,
vulnerabilitiesAllowed
:
res
.
vulnerabilities_allowed
,
severityLevels
:
res
.
severity_levels
,
});
export
const
mapApprovalSettingsResponse
=
(
res
)
=>
({
...
...
ee/spec/frontend/approvals/components/rule_form_spec.js
View file @
9dee2023
...
...
@@ -41,6 +41,7 @@ const TEST_RULE_VULNERABILITY_CHECK = {
name
:
VULNERABILITY_CHECK_NAME
,
scanners
:
[
'
sast
'
,
'
dast
'
],
vulnerabilitiesAllowed
:
0
,
severityLevels
:
[
'
high
'
],
};
const
TEST_APPROVERS
=
[{
id
:
7
,
type
:
TYPE_USER
}];
const
TEST_APPROVALS_REQUIRED
=
3
;
...
...
@@ -99,6 +100,7 @@ describe('EE Approvals RuleForm', () => {
const
findBranchesValidation
=
()
=>
wrapper
.
findByTestId
(
'
branches-group
'
);
const
findScannersGroup
=
()
=>
wrapper
.
findByTestId
(
'
scanners-group
'
);
const
findVulnerabilityFormGroup
=
()
=>
wrapper
.
findByTestId
(
'
vulnerability-amount-group
'
);
const
findSeverityLevelsGroup
=
()
=>
wrapper
.
findByTestId
(
'
severity-levels-group
'
);
const
inputsAreValid
=
(
inputs
)
=>
inputs
.
every
((
x
)
=>
x
.
props
(
'
state
'
));
...
...
@@ -203,6 +205,7 @@ describe('EE Approvals RuleForm', () => {
groupRecords
,
removeHiddenGroups
:
false
,
scanners
:
[],
severityLevels
:
[],
protectedBranchIds
:
branches
.
map
((
x
)
=>
x
.
id
),
};
...
...
@@ -282,6 +285,7 @@ describe('EE Approvals RuleForm', () => {
groupRecords
,
removeHiddenGroups
:
false
,
scanners
:
[],
severityLevels
:
[],
protectedBranchIds
:
branches
.
map
((
x
)
=>
x
.
id
),
};
...
...
@@ -362,6 +366,7 @@ describe('EE Approvals RuleForm', () => {
groupRecords
,
removeHiddenGroups
:
false
,
scanners
:
[],
severityLevels
:
[],
protectedBranchIds
:
[],
};
...
...
@@ -539,11 +544,11 @@ describe('EE Approvals RuleForm', () => {
describe
(
'
with approval suggestions
'
,
()
=>
{
describe
.
each
`
defaultRuleName | expectedDisabledAttribute | expectedDisplayedScanners | expectedDisplayVulnerabilityAllowed
${
VULNERABILITY_CHECK_NAME
}
|
${
true
}
|
${
true
}
|
${
true
}
${
'
License-Check
'
}
|
${
true
}
|
${
false
}
|
${
false
}
${
'
Coverage-Check
'
}
|
${
true
}
|
${
false
}
|
${
false
}
${
'
Foo Bar Baz
'
}
|
${
false
}
|
${
false
}
|
${
false
}
defaultRuleName | expectedDisabledAttribute | expectedDisplayedScanners | expectedDisplayVulnerabilityAllowed
| expectedDisplayedSeverityLevels
${
VULNERABILITY_CHECK_NAME
}
|
${
true
}
|
${
true
}
|
${
true
}
|
${
true
}
${
'
License-Check
'
}
|
${
true
}
|
${
false
}
|
${
false
}
|
${
false
}
${
'
Coverage-Check
'
}
|
${
true
}
|
${
false
}
|
${
false
}
|
${
false
}
${
'
Foo Bar Baz
'
}
|
${
false
}
|
${
false
}
|
${
false
}
|
${
false
}
`
(
'
with defaultRuleName set to $defaultRuleName
'
,
({
...
...
@@ -551,6 +556,7 @@ describe('EE Approvals RuleForm', () => {
expectedDisabledAttribute
,
expectedDisplayedScanners
,
expectedDisplayVulnerabilityAllowed
,
expectedDisplayedSeverityLevels
,
})
=>
{
beforeEach
(()
=>
{
createComponent
({
...
...
@@ -575,6 +581,11 @@ describe('EE Approvals RuleForm', () => {
}
the number of vulnerabilities form group`
,
()
=>
{
expect
(
findVulnerabilityFormGroup
().
exists
()).
toBe
(
expectedDisplayVulnerabilityAllowed
);
});
it
(
`it
${
expectedDisplayedSeverityLevels
?
'
shows
'
:
'
does not show
'
}
severity levels dropdown`
,
()
=>
{
expect
(
findSeverityLevelsGroup
().
exists
()).
toBe
(
expectedDisplayedSeverityLevels
);
});
},
);
});
...
...
@@ -672,7 +683,41 @@ describe('EE Approvals RuleForm', () => {
it
(
'
contains the supported report types and select all option
'
,
()
=>
{
const
supportedReportsPlusAll
=
Object
.
keys
(
REPORT_TYPES
).
length
-
[
EXCLUDED_REPORT_TYPE
].
length
+
1
;
expect
(
wrapper
.
findAllComponents
(
GlTruncate
)).
toHaveLength
(
supportedReportsPlusAll
);
expect
(
findScannersGroup
().
findAllComponents
(
GlTruncate
)).
toHaveLength
(
supportedReportsPlusAll
,
);
});
});
describe
(
'
and without any severity levels selected
'
,
()
=>
{
beforeEach
(()
=>
{
createComponent
({
initRule
:
{
...
TEST_RULE_VULNERABILITY_CHECK
,
severityLevels
:
[],
},
});
findForm
().
trigger
(
'
submit
'
);
});
it
(
'
does not dispatch the action on submit
'
,
()
=>
{
expect
(
actions
.
postRule
).
not
.
toHaveBeenCalled
();
});
});
describe
(
'
with one severity level selected
'
,
()
=>
{
beforeEach
(()
=>
{
createComponent
({
initRule
:
TEST_RULE_VULNERABILITY_CHECK
,
});
findForm
().
trigger
(
'
submit
'
);
});
it
(
'
dispatches the action on submit
'
,
()
=>
{
expect
(
actions
.
postRule
).
toHaveBeenCalledWith
(
expect
.
anything
(),
expect
.
objectContaining
({
severityLevels
:
[
'
high
'
]
}),
);
});
});
});
...
...
locale/gitlab.pot
View file @
9dee2023
...
...
@@ -4166,7 +4166,7 @@ msgid_plural "ApprovalRuleSummary|%{count} approvals required from %{membersCoun
msgstr[0] ""
msgstr[1] ""
msgid "ApprovalRule|%{
scanner} +%{additionalScanner
s} more"
msgid "ApprovalRule|%{
firstLabel} +%{numberOfAdditionalLabel
s} more"
msgstr ""
msgid "ApprovalRule|Add approvers"
...
...
@@ -4175,9 +4175,15 @@ msgstr ""
msgid "ApprovalRule|All scanners"
msgstr ""
msgid "ApprovalRule|All severity levels"
msgstr ""
msgid "ApprovalRule|Apply this approval rule to consider only the selected security scanners."
msgstr ""
msgid "ApprovalRule|Apply this approval rule to consider only the selected severity levels."
msgstr ""
msgid "ApprovalRule|Approval rules"
msgstr ""
...
...
@@ -4205,6 +4211,9 @@ msgstr ""
msgid "ApprovalRule|Please select at least one security scanner"
msgstr ""
msgid "ApprovalRule|Please select at least one severity level"
msgstr ""
msgid "ApprovalRule|Rule name"
msgstr ""
...
...
@@ -4217,6 +4226,12 @@ msgstr ""
msgid "ApprovalRule|Select scanners"
msgstr ""
msgid "ApprovalRule|Select severity levels"
msgstr ""
msgid "ApprovalRule|Severity levels"
msgstr ""
msgid "ApprovalRule|Target branch"
msgstr ""
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment