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
0854b021
Commit
0854b021
authored
Oct 28, 2021
by
GitLab Bot
Browse files
Options
Browse Files
Download
Plain Diff
Automatic merge of gitlab-org/gitlab master
parents
b84cd406
b37098e3
Changes
60
Hide whitespace changes
Inline
Side-by-side
Showing
60 changed files
with
936 additions
and
285 deletions
+936
-285
app/assets/javascripts/lib/utils/common_utils.js
app/assets/javascripts/lib/utils/common_utils.js
+11
-8
app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/store/mutations.js
...d/components/sidebar/labels_select_vue/store/mutations.js
+4
-3
app/models/concerns/enums/vulnerability.rb
app/models/concerns/enums/vulnerability.rb
+13
-0
app/workers/concerns/application_worker.rb
app/workers/concerns/application_worker.rb
+25
-5
db/migrate/20211013192749_add_states_into_approval_project_rules.rb
.../20211013192749_add_states_into_approval_project_rules.rb
+11
-0
db/schema_migrations/20211013192749
db/schema_migrations/20211013192749
+1
-0
db/structure.sql
db/structure.sql
+2
-1
doc/development/documentation/site_architecture/index.md
doc/development/documentation/site_architecture/index.md
+29
-0
ee/app/assets/javascripts/approvals/components/rule_form.vue
ee/app/assets/javascripts/approvals/components/rule_form.vue
+88
-21
ee/app/assets/javascripts/approvals/constants.js
ee/app/assets/javascripts/approvals/constants.js
+15
-0
ee/app/assets/javascripts/approvals/mappers.js
ee/app/assets/javascripts/approvals/mappers.js
+6
-23
ee/app/models/approval_project_rule.rb
ee/app/models/approval_project_rule.rb
+13
-0
ee/app/models/ci/minutes/namespace_monthly_usage.rb
ee/app/models/ci/minutes/namespace_monthly_usage.rb
+4
-3
ee/app/models/ci/minutes/project_monthly_usage.rb
ee/app/models/ci/minutes/project_monthly_usage.rb
+4
-3
ee/app/models/ee/vulnerability.rb
ee/app/models/ee/vulnerability.rb
+2
-3
ee/app/services/ci/minutes/update_project_and_namespace_usage_service.rb
.../ci/minutes/update_project_and_namespace_usage_service.rb
+14
-5
ee/app/services/ci/sync_reports_to_approval_rules_service.rb
ee/app/services/ci/sync_reports_to_approval_rules_service.rb
+8
-2
ee/app/workers/ci/minutes/update_project_and_namespace_usage_worker.rb
...s/ci/minutes/update_project_and_namespace_usage_worker.rb
+2
-2
ee/app/workers/project_import_schedule_worker.rb
ee/app/workers/project_import_schedule_worker.rb
+1
-0
ee/config/metrics/license/20210204124831_license_md5.yml
ee/config/metrics/license/20210204124831_license_md5.yml
+6
-4
ee/config/metrics/license/20210204124833_license_id.yml
ee/config/metrics/license/20210204124833_license_id.yml
+3
-0
ee/config/metrics/license/20210204124843_license_user_count.yml
...fig/metrics/license/20210204124843_license_user_count.yml
+3
-0
ee/config/metrics/license/20210204124845_license_starts_at.yml
...nfig/metrics/license/20210204124845_license_starts_at.yml
+3
-0
ee/config/metrics/license/20210204124847_license_expires_at.yml
...fig/metrics/license/20210204124847_license_expires_at.yml
+3
-0
ee/config/metrics/license/20210204124849_license_plan.yml
ee/config/metrics/license/20210204124849_license_plan.yml
+3
-0
ee/config/metrics/license/20210204124851_license_trial.yml
ee/config/metrics/license/20210204124851_license_trial.yml
+3
-0
ee/config/metrics/license/20210204124852_license_subscription_id.yml
...etrics/license/20210204124852_license_subscription_id.yml
+3
-1
ee/config/metrics/license/20210204124926_license_trial_ends_on.yml
.../metrics/license/20210204124926_license_trial_ends_on.yml
+3
-0
ee/lib/api/helpers/project_approval_rules_helpers.rb
ee/lib/api/helpers/project_approval_rules_helpers.rb
+2
-0
ee/lib/ee/api/entities/project_approval_setting_rule.rb
ee/lib/ee/api/entities/project_approval_setting_rule.rb
+1
-0
ee/lib/ee/gitlab/ci/reports/security/reports.rb
ee/lib/ee/gitlab/ci/reports/security/reports.rb
+35
-0
ee/lib/ee/gitlab/usage_data.rb
ee/lib/ee/gitlab/usage_data.rb
+3
-3
ee/lib/gitlab/usage/metrics/instrumentations/license_md_five_metric.rb
.../usage/metrics/instrumentations/license_md_five_metric.rb
+0
-15
ee/lib/gitlab/usage/metrics/instrumentations/license_metric.rb
...b/gitlab/usage/metrics/instrumentations/license_metric.rb
+51
-0
ee/lib/gitlab/usage/metrics/instrumentations/zuora_subscription_id_metric.rb
.../metrics/instrumentations/zuora_subscription_id_metric.rb
+0
-15
ee/spec/fixtures/api/schemas/public_api/v4/project_approval_setting.json
...s/api/schemas/public_api/v4/project_approval_setting.json
+6
-0
ee/spec/frontend/approvals/components/rule_form_spec.js
ee/spec/frontend/approvals/components/rule_form_spec.js
+104
-21
ee/spec/frontend/approvals/mocks.js
ee/spec/frontend/approvals/mocks.js
+25
-0
ee/spec/lib/ee/gitlab/ci/reports/security/reports_spec.rb
ee/spec/lib/ee/gitlab/ci/reports/security/reports_spec.rb
+79
-0
ee/spec/lib/ee/gitlab/usage_data_spec.rb
ee/spec/lib/ee/gitlab/usage_data_spec.rb
+4
-0
ee/spec/lib/gitlab/usage/metrics/instrumentations/license_md_five_metric_spec.rb
...e/metrics/instrumentations/license_md_five_metric_spec.rb
+0
-9
ee/spec/lib/gitlab/usage/metrics/instrumentations/zuora_subscription_id_metric_spec.rb
...ics/instrumentations/zuora_subscription_id_metric_spec.rb
+0
-9
ee/spec/models/approval_project_rule_spec.rb
ee/spec/models/approval_project_rule_spec.rb
+40
-11
ee/spec/models/ci/minutes/namespace_monthly_usage_spec.rb
ee/spec/models/ci/minutes/namespace_monthly_usage_spec.rb
+1
-21
ee/spec/models/ci/minutes/project_monthly_usage_spec.rb
ee/spec/models/ci/minutes/project_monthly_usage_spec.rb
+5
-21
ee/spec/models/ee/vulnerability_spec.rb
ee/spec/models/ee/vulnerability_spec.rb
+22
-0
ee/spec/services/ci/minutes/update_project_and_namespace_usage_service_spec.rb
...inutes/update_project_and_namespace_usage_service_spec.rb
+15
-4
ee/spec/services/ci/sync_reports_to_approval_rules_service_spec.rb
...ervices/ci/sync_reports_to_approval_rules_service_spec.rb
+11
-1
ee/spec/support/shared_examples/models/ci/increase_usage_shared_examples.rb
...ared_examples/models/ci/increase_usage_shared_examples.rb
+76
-0
ee/spec/workers/ci/minutes/update_project_and_namespace_usage_worker_spec.rb
...minutes/update_project_and_namespace_usage_worker_spec.rb
+58
-15
lib/gitlab/ci/reports/security/reports.rb
lib/gitlab/ci/reports/security/reports.rb
+11
-8
lib/gitlab/usage/metrics/names_suggestions/generator.rb
lib/gitlab/usage/metrics/names_suggestions/generator.rb
+2
-2
lib/gitlab/usage_data_non_sql_metrics.rb
lib/gitlab/usage_data_non_sql_metrics.rb
+2
-2
lib/gitlab/usage_data_queries.rb
lib/gitlab/usage_data_queries.rb
+2
-2
lib/gitlab/utils/usage_data.rb
lib/gitlab/utils/usage_data.rb
+2
-2
locale/gitlab.pot
locale/gitlab.pot
+30
-0
spec/frontend/lib/utils/common_utils_spec.js
spec/frontend/lib/utils/common_utils_spec.js
+15
-0
spec/frontend/vue_shared/components/sidebar/labels_select_vue/store/mutations_spec.js
...ponents/sidebar/labels_select_vue/store/mutations_spec.js
+33
-39
spec/lib/gitlab/ci/reports/security/reports_spec.rb
spec/lib/gitlab/ci/reports/security/reports_spec.rb
+2
-1
spec/workers/concerns/application_worker_spec.rb
spec/workers/concerns/application_worker_spec.rb
+16
-0
No files found.
app/assets/javascripts/lib/utils/common_utils.js
View file @
0854b021
...
@@ -688,17 +688,20 @@ export const searchBy = (query = '', searchSpace = {}) => {
...
@@ -688,17 +688,20 @@ export const searchBy = (query = '', searchSpace = {}) => {
*/
*/
export
const
isScopedLabel
=
({
title
=
''
}
=
{})
=>
title
.
includes
(
SCOPED_LABEL_DELIMITER
);
export
const
isScopedLabel
=
({
title
=
''
}
=
{})
=>
title
.
includes
(
SCOPED_LABEL_DELIMITER
);
const
scopedLabelRegex
=
new
RegExp
(
`(.*)
${
SCOPED_LABEL_DELIMITER
}
.*`
);
/**
/**
* Returns the
base value of the scoped label
* Returns the
key of a scoped label.
*
*
For example:
*
Expected Label to be an Object with `title` as a key:
*
- returns `scoped` if the label is `scoped::value`.
*
{ title: 'LabelTitle', ...otherProperties };
*
- returns `scoped::label` if the label is `scoped::label::value`.
*
*
* @param {Object} label
* @param {Object} label
object containing `title` property
* @returns String
* @returns String
scoped label key, or full label if it is not a scoped label
*/
*/
export
const
scopedLabelKey
=
({
title
=
''
})
=>
export
const
scopedLabelKey
=
({
title
=
''
})
=>
{
isScopedLabel
({
title
})
&&
title
.
split
(
SCOPED_LABEL_DELIMITER
)[
0
];
return
title
.
replace
(
scopedLabelRegex
,
'
$1
'
);
};
// Methods to set and get Cookie
// Methods to set and get Cookie
export
const
setCookie
=
(
name
,
value
)
=>
Cookies
.
set
(
name
,
value
,
{
expires
:
365
});
export
const
setCookie
=
(
name
,
value
)
=>
Cookies
.
set
(
name
,
value
,
{
expires
:
365
});
...
...
app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/store/mutations.js
View file @
0854b021
import
{
isScopedLabel
,
scopedLabelKey
}
from
'
~/lib/utils/common_utils
'
;
import
{
isScopedLabel
,
scopedLabelKey
}
from
'
~/lib/utils/common_utils
'
;
import
{
SCOPED_LABEL_DELIMITER
}
from
'
~/vue_shared/components/sidebar/labels_select_widget/constants
'
;
import
{
DropdownVariant
}
from
'
../constants
'
;
import
{
DropdownVariant
}
from
'
../constants
'
;
import
*
as
types
from
'
./mutation_types
'
;
import
*
as
types
from
'
./mutation_types
'
;
...
@@ -67,9 +66,11 @@ export default {
...
@@ -67,9 +66,11 @@ export default {
}
}
if
(
isScopedLabel
(
candidateLabel
))
{
if
(
isScopedLabel
(
candidateLabel
))
{
const
scopedKeyWithDelimiter
=
`
${
scopedLabelKey
(
candidateLabel
)}${
SCOPED_LABEL_DELIMITER
}
`
;
const
currentActiveScopedLabel
=
state
.
labels
.
find
(
const
currentActiveScopedLabel
=
state
.
labels
.
find
(
({
title
})
=>
title
.
startsWith
(
scopedKeyWithDelimiter
)
&&
title
!==
candidateLabel
.
title
,
({
set
,
title
})
=>
set
&&
title
!==
candidateLabel
.
title
&&
scopedLabelKey
({
title
})
===
scopedLabelKey
(
candidateLabel
),
);
);
if
(
currentActiveScopedLabel
)
{
if
(
currentActiveScopedLabel
)
{
...
...
app/models/concerns/enums/vulnerability.rb
View file @
0854b021
...
@@ -37,6 +37,15 @@ module Enums
...
@@ -37,6 +37,15 @@ module Enums
security_audit:
4
security_audit:
4
}.
with_indifferent_access
.
freeze
}.
with_indifferent_access
.
freeze
# keep the order of the values in the state enum, it is used in state_order method to properly order vulnerabilities based on state
# remember to recreate index_vulnerabilities_on_state_case_id index when you update or extend this enum
VULNERABILITY_STATES
=
{
detected:
1
,
confirmed:
4
,
resolved:
3
,
dismissed:
2
}.
with_indifferent_access
.
freeze
def
self
.
confidence_levels
def
self
.
confidence_levels
CONFIDENCE_LEVELS
CONFIDENCE_LEVELS
end
end
...
@@ -52,6 +61,10 @@ module Enums
...
@@ -52,6 +61,10 @@ module Enums
def
self
.
detection_methods
def
self
.
detection_methods
DETECTION_METHODS
DETECTION_METHODS
end
end
def
self
.
vulnerability_states
VULNERABILITY_STATES
end
end
end
end
end
...
...
app/workers/concerns/application_worker.rb
View file @
0854b021
...
@@ -131,17 +131,27 @@ module ApplicationWorker
...
@@ -131,17 +131,27 @@ module ApplicationWorker
end
end
end
end
def
log_bulk_perform_async?
@log_bulk_perform_async
end
def
log_bulk_perform_async!
@log_bulk_perform_async
=
true
end
def
queue_size
def
queue_size
Sidekiq
::
Queue
.
new
(
queue
).
size
Sidekiq
::
Queue
.
new
(
queue
).
size
end
end
def
bulk_perform_async
(
args_list
)
def
bulk_perform_async
(
args_list
)
if
Feature
.
enabled?
(
:sidekiq_push_bulk_in_batches
)
if
log_bulk_perform_async?
in_safe_limit_batches
(
args_list
)
do
|
args_batch
,
_
|
Sidekiq
.
logger
.
info
(
'class'
=>
self
,
'args_list'
=>
args_list
,
'args_list_count'
=>
args_list
.
length
,
'message'
=>
'Inserting multiple jobs'
)
Sidekiq
::
Client
.
push_bulk
(
'class'
=>
self
,
'args'
=>
args_batch
)
end
do_push_bulk
(
args_list
).
tap
do
|
job_ids
|
if
log_bulk_perform_async?
Sidekiq
.
logger
.
info
(
'class'
=>
self
,
'jid_list'
=>
job_ids
,
'jid_list_count'
=>
job_ids
.
length
,
'message'
=>
'Completed JID insertion'
)
end
end
else
Sidekiq
::
Client
.
push_bulk
(
'class'
=>
self
,
'args'
=>
args_list
)
end
end
end
end
...
@@ -188,6 +198,16 @@ module ApplicationWorker
...
@@ -188,6 +198,16 @@ module ApplicationWorker
private
private
def
do_push_bulk
(
args_list
)
if
Feature
.
enabled?
(
:sidekiq_push_bulk_in_batches
)
in_safe_limit_batches
(
args_list
)
do
|
args_batch
,
_
|
Sidekiq
::
Client
.
push_bulk
(
'class'
=>
self
,
'args'
=>
args_batch
)
end
else
Sidekiq
::
Client
.
push_bulk
(
'class'
=>
self
,
'args'
=>
args_list
)
end
end
def
in_safe_limit_batches
(
args_list
,
schedule_at
=
nil
,
safe_limit
=
SAFE_PUSH_BULK_LIMIT
)
def
in_safe_limit_batches
(
args_list
,
schedule_at
=
nil
,
safe_limit
=
SAFE_PUSH_BULK_LIMIT
)
# `schedule_at` could be one of
# `schedule_at` could be one of
# - nil.
# - nil.
...
...
db/migrate/20211013192749_add_states_into_approval_project_rules.rb
0 → 100644
View file @
0854b021
# frozen_string_literal: true
class
AddStatesIntoApprovalProjectRules
<
Gitlab
::
Database
::
Migration
[
1.0
]
def
up
add_column
:approval_project_rules
,
:vulnerability_states
,
:text
,
array:
true
,
null:
false
,
default:
[
'newly_detected'
]
end
def
down
remove_column
:approval_project_rules
,
:vulnerability_states
end
end
db/schema_migrations/20211013192749
0 → 100644
View file @
0854b021
eeda27c42a80d23851bb58b00cee79feeffbe9ae1fef76b3034f92c8610a8aaf
\ No newline at end of file
db/structure.sql
View file @
0854b021
...
@@ -10579,7 +10579,8 @@ CREATE TABLE approval_project_rules (
...
@@ -10579,7 +10579,8 @@ CREATE TABLE approval_project_rules (
scanners text[],
scanners text[],
vulnerabilities_allowed smallint DEFAULT 0 NOT NULL,
vulnerabilities_allowed smallint DEFAULT 0 NOT NULL,
severity_levels text[] DEFAULT '{}'::text[] NOT NULL,
severity_levels text[] DEFAULT '{}'::text[] NOT NULL,
report_type smallint
report_type smallint,
vulnerability_states text[] DEFAULT '{newly_detected}'::text[] NOT NULL
);
);
CREATE TABLE approval_project_rules_groups (
CREATE TABLE approval_project_rules_groups (
doc/development/documentation/site_architecture/index.md
View file @
0854b021
...
@@ -163,6 +163,35 @@ We can then loop over the `versions` array with something like:
...
@@ -163,6 +163,35 @@ We can then loop over the `versions` array with something like:
Note that the data file must have the
`yaml`
extension (not
`yml`
) and that
Note that the data file must have the
`yaml`
extension (not
`yml`
) and that
we reference the array with a symbol (
`:versions`
).
we reference the array with a symbol (
`:versions`
).
## Archived documentation banner
A banner is displayed on archived documentation pages with the text
`This is archived documentation for
GitLab. Go to the latest.`
when either:
-
The version of the documentation displayed is not the first version entry in
`online`
in
`content/_data/versions.yaml`
.
-
The documentation was built from the default branch (
`main`
).
For example, if the
`online`
entries for
`content/_data/versions.yaml`
are:
```
yaml
online
:
-
"
14.4"
-
"
14.3"
-
"
14.2"
```
In this case, the archived documentation banner isn't displayed:
-
For 14.4, the docs built from the
`14.4`
branch. The branch name is the first entry in
`online`
.
-
For 14.5-pre, the docs built from the default project branch (
`main`
).
The archived documentation banner is displayed:
-
For 14.3.
-
For 14.2.
-
For any other version.
## Bumping versions of CSS and JavaScript
## Bumping versions of CSS and JavaScript
Whenever the custom CSS and JavaScript files under
`content/assets/`
change,
Whenever the custom CSS and JavaScript files under
`content/assets/`
change,
...
...
ee/app/assets/javascripts/approvals/components/rule_form.vue
View file @
0854b021
...
@@ -14,6 +14,7 @@ import {
...
@@ -14,6 +14,7 @@ import {
VULNERABILITY_CHECK_NAME
,
VULNERABILITY_CHECK_NAME
,
COVERAGE_CHECK_NAME
,
COVERAGE_CHECK_NAME
,
APPROVAL_DIALOG_I18N
,
APPROVAL_DIALOG_I18N
,
APPROVAL_VULNERABILITY_STATES
,
}
from
'
../constants
'
;
}
from
'
../constants
'
;
import
ApproversList
from
'
./approvers_list.vue
'
;
import
ApproversList
from
'
./approvers_list.vue
'
;
import
ApproversSelect
from
'
./approvers_select.vue
'
;
import
ApproversSelect
from
'
./approvers_select.vue
'
;
...
@@ -72,6 +73,10 @@ export default {
...
@@ -72,6 +73,10 @@ export default {
serverValidationErrors
:
[],
serverValidationErrors
:
[],
scanners
:
[],
scanners
:
[],
severityLevels
:
[],
severityLevels
:
[],
vulnerabilityStates
:
[],
approvalVulnerabilityStatesKeys
:
Object
.
keys
(
APPROVAL_VULNERABILITY_STATES
),
reportTypesKeys
:
Object
.
keys
(
REPORT_TYPES
),
severityLevelsKeys
:
Object
.
keys
(
SEVERITY_LEVELS
),
...
this
.
getInitialData
(),
...
this
.
getInitialData
(),
};
};
},
},
...
@@ -144,11 +149,7 @@ export default {
...
@@ -144,11 +149,7 @@ export default {
return
''
;
return
''
;
},
},
invalidScanners
()
{
invalidScanners
()
{
if
(
this
.
scanners
.
length
<=
0
)
{
return
this
.
scanners
.
length
<=
0
;
return
APPROVAL_DIALOG_I18N
.
validations
.
scannersRequired
;
}
return
''
;
},
},
invalidVulnerabilitiesAllowedError
()
{
invalidVulnerabilitiesAllowedError
()
{
if
(
!
isNumber
(
this
.
vulnerabilitiesAllowed
))
{
if
(
!
isNumber
(
this
.
vulnerabilitiesAllowed
))
{
...
@@ -161,11 +162,10 @@ export default {
...
@@ -161,11 +162,10 @@ export default {
return
''
;
return
''
;
},
},
invalidSeverityLevels
()
{
invalidSeverityLevels
()
{
if
(
this
.
severityLevels
.
length
===
0
)
{
return
this
.
severityLevels
.
length
===
0
;
return
APPROVAL_DIALOG_I18N
.
validations
.
severityLevelsRequired
;
},
}
invalidVulnerabilityStates
()
{
return
this
.
vulnerabilityStates
.
length
===
0
;
return
''
;
},
},
isValid
()
{
isValid
()
{
return
(
return
(
...
@@ -175,7 +175,8 @@ export default {
...
@@ -175,7 +175,8 @@ export default {
this
.
isValidApprovers
&&
this
.
isValidApprovers
&&
this
.
areValidScanners
&&
this
.
areValidScanners
&&
this
.
isValidVulnerabilitiesAllowed
&&
this
.
isValidVulnerabilitiesAllowed
&&
this
.
areValidSeverityLevels
this
.
areValidSeverityLevels
&&
this
.
areValidVulnerabilityStates
);
);
},
},
isValidName
()
{
isValidName
()
{
...
@@ -203,6 +204,9 @@ export default {
...
@@ -203,6 +204,9 @@ export default {
areValidSeverityLevels
()
{
areValidSeverityLevels
()
{
return
!
this
.
showValidation
||
!
this
.
isVulnerabilityCheck
||
!
this
.
invalidSeverityLevels
;
return
!
this
.
showValidation
||
!
this
.
isVulnerabilityCheck
||
!
this
.
invalidSeverityLevels
;
},
},
areValidVulnerabilityStates
()
{
return
!
this
.
showValidation
||
!
this
.
isVulnerabilityCheck
||
!
this
.
invalidVulnerabilityStates
;
},
isMultiSubmission
()
{
isMultiSubmission
()
{
return
this
.
settings
.
allowMultiRule
&&
!
this
.
isFallbackSubmission
;
return
this
.
settings
.
allowMultiRule
&&
!
this
.
isFallbackSubmission
;
},
},
...
@@ -242,6 +246,7 @@ export default {
...
@@ -242,6 +246,7 @@ export default {
protectedBranchIds
:
this
.
branches
.
map
((
x
)
=>
x
.
id
),
protectedBranchIds
:
this
.
branches
.
map
((
x
)
=>
x
.
id
),
scanners
:
this
.
scanners
,
scanners
:
this
.
scanners
,
severityLevels
:
this
.
severityLevels
,
severityLevels
:
this
.
severityLevels
,
vulnerabilityStates
:
this
.
vulnerabilityStates
,
};
};
},
},
isEditing
()
{
isEditing
()
{
...
@@ -251,11 +256,11 @@ export default {
...
@@ -251,11 +256,11 @@ export default {
return
VULNERABILITY_CHECK_NAME
===
this
.
name
;
return
VULNERABILITY_CHECK_NAME
===
this
.
name
;
},
},
areAllScannersSelected
()
{
areAllScannersSelected
()
{
return
this
.
scanners
.
length
===
Object
.
values
(
this
.
$options
.
REPORT_TYPES
)
.
length
;
return
this
.
scanners
.
length
===
this
.
reportTypesKeys
.
length
;
},
},
scannersText
()
{
scannersText
()
{
switch
(
this
.
scanners
.
length
)
{
switch
(
this
.
scanners
.
length
)
{
case
Object
.
values
(
this
.
$options
.
REPORT_TYPES
)
.
length
:
case
this
.
reportTypesKeys
.
length
:
return
APPROVAL_DIALOG_I18N
.
form
.
allScannersSelectedLabel
;
return
APPROVAL_DIALOG_I18N
.
form
.
allScannersSelectedLabel
;
case
0
:
case
0
:
return
APPROVAL_DIALOG_I18N
.
form
.
scannersSelectLabel
;
return
APPROVAL_DIALOG_I18N
.
form
.
scannersSelectLabel
;
...
@@ -269,11 +274,11 @@ export default {
...
@@ -269,11 +274,11 @@ export default {
}
}
},
},
areAllSeverityLevelsSelected
()
{
areAllSeverityLevelsSelected
()
{
return
this
.
severityLevels
.
length
===
Object
.
values
(
this
.
$options
.
SEVERITY_LEVELS
)
.
length
;
return
this
.
severityLevels
.
length
===
this
.
severityLevelsKeys
.
length
;
},
},
severityLevelsText
()
{
severityLevelsText
()
{
switch
(
this
.
severityLevels
.
length
)
{
switch
(
this
.
severityLevels
.
length
)
{
case
Object
.
keys
(
this
.
$options
.
SEVERITY_LEVELS
)
.
length
:
case
this
.
severityLevelsKeys
.
length
:
return
APPROVAL_DIALOG_I18N
.
form
.
allSeverityLevelsSelectedLabel
;
return
APPROVAL_DIALOG_I18N
.
form
.
allSeverityLevelsSelectedLabel
;
case
0
:
case
0
:
return
APPROVAL_DIALOG_I18N
.
form
.
severityLevelsSelectLabel
;
return
APPROVAL_DIALOG_I18N
.
form
.
severityLevelsSelectLabel
;
...
@@ -286,6 +291,24 @@ export default {
...
@@ -286,6 +291,24 @@ export default {
});
});
}
}
},
},
vulnerabilityStatesText
()
{
switch
(
this
.
vulnerabilityStates
.
length
)
{
case
this
.
approvalVulnerabilityStatesKeys
.
length
:
return
APPROVAL_DIALOG_I18N
.
form
.
allVulnerabilityStatesSelectedLabel
;
case
0
:
return
APPROVAL_DIALOG_I18N
.
form
.
vulnerabilityStatesSelectLabel
;
case
1
:
return
APPROVAL_VULNERABILITY_STATES
[
this
.
vulnerabilityStates
[
0
]];
default
:
return
sprintf
(
APPROVAL_DIALOG_I18N
.
form
.
multipleSelectedLabel
,
{
firstLabel
:
APPROVAL_VULNERABILITY_STATES
[
this
.
vulnerabilityStates
[
0
]],
numberOfAdditionalLabels
:
this
.
vulnerabilityStates
.
length
-
1
,
});
}
},
areAllVulnerabilityStatesSelected
()
{
return
this
.
vulnerabilityStates
.
length
===
this
.
approvalVulnerabilityStatesKeys
.
length
;
},
},
},
watch
:
{
watch
:
{
approversToAdd
(
value
)
{
approversToAdd
(
value
)
{
...
@@ -404,10 +427,11 @@ export default {
...
@@ -404,10 +427,11 @@ export default {
scanners
:
this
.
initRule
.
scanners
||
[],
scanners
:
this
.
initRule
.
scanners
||
[],
vulnerabilitiesAllowed
:
this
.
initRule
.
vulnerabilitiesAllowed
||
0
,
vulnerabilitiesAllowed
:
this
.
initRule
.
vulnerabilitiesAllowed
||
0
,
severityLevels
:
this
.
initRule
.
severityLevels
||
[],
severityLevels
:
this
.
initRule
.
severityLevels
||
[],
vulnerabilityStates
:
this
.
initRule
.
vulnerabilityStates
||
[],
};
};
},
},
setAllSelectedScanners
()
{
setAllSelectedScanners
()
{
this
.
scanners
=
this
.
areAllScannersSelected
?
[]
:
Object
.
keys
(
this
.
$options
.
REPORT_TYPES
)
;
this
.
scanners
=
this
.
areAllScannersSelected
?
[]
:
this
.
reportTypesKeys
;
},
},
isScannerSelected
(
scanner
)
{
isScannerSelected
(
scanner
)
{
return
this
.
scanners
.
includes
(
scanner
);
return
this
.
scanners
.
includes
(
scanner
);
...
@@ -421,9 +445,7 @@ export default {
...
@@ -421,9 +445,7 @@ export default {
}
}
},
},
setAllSelectedSeverityLevels
()
{
setAllSelectedSeverityLevels
()
{
this
.
severityLevels
=
this
.
areAllSeverityLevelsSelected
this
.
severityLevels
=
this
.
areAllSeverityLevelsSelected
?
[]
:
this
.
severityLevelsKeys
;
?
[]
:
Object
.
keys
(
this
.
$options
.
SEVERITY_LEVELS
);
},
},
isSeveritySelected
(
severity
)
{
isSeveritySelected
(
severity
)
{
return
this
.
severityLevels
.
includes
(
severity
);
return
this
.
severityLevels
.
includes
(
severity
);
...
@@ -436,10 +458,27 @@ export default {
...
@@ -436,10 +458,27 @@ export default {
this
.
severityLevels
.
splice
(
pos
,
1
);
this
.
severityLevels
.
splice
(
pos
,
1
);
}
}
},
},
setAllSelectedVulnerabilityStates
()
{
this
.
vulnerabilityStates
=
this
.
areAllVulnerabilityStatesSelected
?
[]
:
this
.
approvalVulnerabilityStatesKeys
;
},
isVulnerabilityStateSelected
(
vulnerability
)
{
return
this
.
vulnerabilityStates
.
includes
(
vulnerability
);
},
setVulnerabilityState
(
vulnerability
)
{
const
pos
=
this
.
vulnerabilityStates
.
indexOf
(
vulnerability
);
if
(
pos
===
-
1
)
{
this
.
vulnerabilityStates
.
push
(
vulnerability
);
}
else
{
this
.
vulnerabilityStates
.
splice
(
pos
,
1
);
}
},
},
},
APPROVAL_DIALOG_I18N
,
APPROVAL_DIALOG_I18N
,
REPORT_TYPES
:
omit
(
REPORT_TYPES
,
EXCLUDED_REPORT_TYPE
),
REPORT_TYPES
:
omit
(
REPORT_TYPES
,
EXCLUDED_REPORT_TYPE
),
SEVERITY_LEVELS
,
SEVERITY_LEVELS
,
APPROVAL_VULNERABILITY_STATES
,
};
};
</
script
>
</
script
>
...
@@ -466,7 +505,7 @@ export default {
...
@@ -466,7 +505,7 @@ export default {
:label=
"$options.APPROVAL_DIALOG_I18N.form.scannersLabel"
:label=
"$options.APPROVAL_DIALOG_I18N.form.scannersLabel"
:description=
"$options.APPROVAL_DIALOG_I18N.form.scannersDescription"
:description=
"$options.APPROVAL_DIALOG_I18N.form.scannersDescription"
:state=
"areValidScanners"
:state=
"areValidScanners"
:invalid-feedback=
"
invalidScanners
"
:invalid-feedback=
"
$options.APPROVAL_DIALOG_I18N.validations.scannersRequired
"
data-testid=
"scanners-group"
data-testid=
"scanners-group"
>
>
<gl-dropdown
:text=
"scannersText"
>
<gl-dropdown
:text=
"scannersText"
>
...
@@ -504,6 +543,34 @@ export default {
...
@@ -504,6 +543,34 @@ export default {
:selected-branches=
"branches"
:selected-branches=
"branches"
/>
/>
</gl-form-group>
</gl-form-group>
<gl-form-group
v-if=
"isVulnerabilityCheck"
:label=
"$options.APPROVAL_DIALOG_I18N.form.vulnerabilityStatesLabel"
:description=
"$options.APPROVAL_DIALOG_I18N.form.vulnerabilityStatesDescription"
:state=
"areValidVulnerabilityStates"
:invalid-feedback=
"$options.APPROVAL_DIALOG_I18N.validations.vulnerabilityStatesRequired"
data-testid=
"vulnerability-states-group"
>
<gl-dropdown
:text=
"vulnerabilityStatesText"
>
<gl-dropdown-item
key=
"all"
is-check-item
:is-checked=
"areAllVulnerabilityStatesSelected"
@
click.native.capture.stop=
"setAllSelectedVulnerabilityStates"
>
<gl-truncate
:text=
"$options.APPROVAL_DIALOG_I18N.form.selectAllLabel"
/>
</gl-dropdown-item>
<gl-dropdown-item
v-for=
"(value, key) in $options.APPROVAL_VULNERABILITY_STATES"
:key=
"key"
is-check-item
:is-checked=
"isVulnerabilityStateSelected(key)"
@
click.native.capture.stop=
"setVulnerabilityState(key)"
>
<gl-truncate
:text=
"value"
/>
</gl-dropdown-item>
</gl-dropdown>
</gl-form-group>
<gl-form-group
<gl-form-group
v-if=
"isVulnerabilityCheck"
v-if=
"isVulnerabilityCheck"
:label=
"$options.APPROVAL_DIALOG_I18N.form.vulnerabilitiesAllowedLabel"
:label=
"$options.APPROVAL_DIALOG_I18N.form.vulnerabilitiesAllowedLabel"
...
@@ -526,7 +593,7 @@ export default {
...
@@ -526,7 +593,7 @@ export default {
:label=
"$options.APPROVAL_DIALOG_I18N.form.severityLevelsLabel"
:label=
"$options.APPROVAL_DIALOG_I18N.form.severityLevelsLabel"
:description=
"$options.APPROVAL_DIALOG_I18N.form.severityLevelsDescription"
:description=
"$options.APPROVAL_DIALOG_I18N.form.severityLevelsDescription"
:state=
"areValidSeverityLevels"
:state=
"areValidSeverityLevels"
:invalid-feedback=
"
invalidSeverityLevels
"
:invalid-feedback=
"
$options.APPROVAL_DIALOG_I18N.validations.severityLevelsRequired
"
data-testid=
"severity-levels-group"
data-testid=
"severity-levels-group"
>
>
<gl-dropdown
:text=
"severityLevelsText"
>
<gl-dropdown
:text=
"severityLevelsText"
>
...
...
ee/app/assets/javascripts/approvals/constants.js
View file @
0854b021
...
@@ -118,6 +118,12 @@ export const APPROVAL_DIALOG_I18N = {
...
@@ -118,6 +118,12 @@ export const APPROVAL_DIALOG_I18N = {
vulnerabilitiesAllowedDescription
:
s__
(
vulnerabilitiesAllowedDescription
:
s__
(
'
ApprovalRule|Number of vulnerabilities allowed before approval rule is triggered.
'
,
'
ApprovalRule|Number of vulnerabilities allowed before approval rule is triggered.
'
,
),
),
vulnerabilityStatesLabel
:
s__
(
'
ApprovalRule|Vulnerability states
'
),
vulnerabilityStatesDescription
:
s__
(
'
ApprovalRule|Apply this approval rule to consider only the selected vulnerability states.
'
,
),
vulnerabilityStatesSelectLabel
:
s__
(
'
ApprovalRule|Select vulnerability states
'
),
allVulnerabilityStatesSelectedLabel
:
s__
(
'
ApprovalRule|All vulnerability states
'
),
severityLevelsLabel
:
s__
(
'
ApprovalRule|Severity levels
'
),
severityLevelsLabel
:
s__
(
'
ApprovalRule|Severity levels
'
),
severityLevelsDescription
:
s__
(
severityLevelsDescription
:
s__
(
'
ApprovalRule|Apply this approval rule to consider only the selected severity levels.
'
,
'
ApprovalRule|Apply this approval rule to consider only the selected severity levels.
'
,
...
@@ -140,5 +146,14 @@ export const APPROVAL_DIALOG_I18N = {
...
@@ -140,5 +146,14 @@ export const APPROVAL_DIALOG_I18N = {
'
ApprovalRule|Please enter a number equal or greater than zero
'
,
'
ApprovalRule|Please enter a number equal or greater than zero
'
,
),
),
severityLevelsRequired
:
s__
(
'
ApprovalRule|Please select at least one severity level
'
),
severityLevelsRequired
:
s__
(
'
ApprovalRule|Please select at least one severity level
'
),
vulnerabilityStatesRequired
:
s__
(
'
ApprovalRule|Please select at least one vulnerability state
'
),
},
},
};
};
export
const
APPROVAL_VULNERABILITY_STATES
=
{
newly_detected
:
s__
(
'
ApprovalRule|Newly detected
'
),
detected
:
s__
(
'
ApprovalRule|Previously detected
'
),
confirmed
:
s__
(
'
ApprovalRule|Confirmed
'
),
dismissed
:
s__
(
'
ApprovalRule|Dismissed
'
),
resolved
:
s__
(
'
ApprovalRule|Resolved
'
),
};
ee/app/assets/javascripts/approvals/mappers.js
View file @
0854b021
import
{
convertObjectPropsToCamelCase
}
from
'
~/lib/utils/common_utils
'
;
import
{
convertObjectPropsToCamelCase
,
convertObjectPropsToSnakeCase
,
}
from
'
~/lib/utils/common_utils
'
;
import
{
import
{
RULE_TYPE_REGULAR
,
RULE_TYPE_REGULAR
,
RULE_TYPE_ANY_APPROVER
,
RULE_TYPE_ANY_APPROVER
,
...
@@ -39,15 +42,7 @@ function reportTypeFromName(ruleName) {
...
@@ -39,15 +42,7 @@ function reportTypeFromName(ruleName) {
}
}
export
const
mapApprovalRuleRequest
=
(
req
)
=>
({
export
const
mapApprovalRuleRequest
=
(
req
)
=>
({
name
:
req
.
name
,
...
convertObjectPropsToSnakeCase
(
req
),
approvals_required
:
req
.
approvalsRequired
,
users
:
req
.
users
,
groups
:
req
.
groups
,
remove_hidden_groups
:
req
.
removeHiddenGroups
,
protected_branch_ids
:
req
.
protectedBranchIds
,
scanners
:
req
.
scanners
,
vulnerabilities_allowed
:
req
.
vulnerabilitiesAllowed
,
severity_levels
:
req
.
severityLevels
,
report_type
:
reportTypeFromName
(
req
.
name
),
report_type
:
reportTypeFromName
(
req
.
name
),
rule_type
:
ruleTypeFromName
(
req
.
name
),
rule_type
:
ruleTypeFromName
(
req
.
name
),
});
});
...
@@ -57,21 +52,9 @@ export const mapApprovalFallbackRuleRequest = (req) => ({
...
@@ -57,21 +52,9 @@ export const mapApprovalFallbackRuleRequest = (req) => ({
});
});
export
const
mapApprovalRuleResponse
=
(
res
)
=>
({
export
const
mapApprovalRuleResponse
=
(
res
)
=>
({
id
:
res
.
id
,
...
convertObjectPropsToCamelCase
(
res
)
,
hasSource
:
Boolean
(
res
.
source_rule
),
hasSource
:
Boolean
(
res
.
source_rule
),
name
:
res
.
name
,
approvalsRequired
:
res
.
approvals_required
,
minApprovalsRequired
:
0
,
minApprovalsRequired
:
0
,
approvers
:
res
.
approvers
,
containsHiddenGroups
:
res
.
contains_hidden_groups
,
users
:
res
.
users
,
groups
:
res
.
groups
,
ruleType
:
res
.
rule_type
,
protectedBranches
:
res
.
protected_branches
,
overridden
:
res
.
overridden
,
scanners
:
res
.
scanners
,
vulnerabilitiesAllowed
:
res
.
vulnerabilities_allowed
,
severityLevels
:
res
.
severity_levels
,
});
});
export
const
mapApprovalSettingsResponse
=
(
res
)
=>
({
export
const
mapApprovalSettingsResponse
=
(
res
)
=>
({
...
...
ee/app/models/approval_project_rule.rb
View file @
0854b021
...
@@ -7,6 +7,9 @@ class ApprovalProjectRule < ApplicationRecord
...
@@ -7,6 +7,9 @@ class ApprovalProjectRule < ApplicationRecord
UNSUPPORTED_SCANNER
=
'cluster_image_scanning'
UNSUPPORTED_SCANNER
=
'cluster_image_scanning'
SUPPORTED_SCANNERS
=
(
::
Ci
::
JobArtifact
::
SECURITY_REPORT_FILE_TYPES
-
[
UNSUPPORTED_SCANNER
]).
freeze
SUPPORTED_SCANNERS
=
(
::
Ci
::
JobArtifact
::
SECURITY_REPORT_FILE_TYPES
-
[
UNSUPPORTED_SCANNER
]).
freeze
DEFAULT_SEVERITIES
=
%w[unknown high critical]
.
freeze
DEFAULT_SEVERITIES
=
%w[unknown high critical]
.
freeze
NEWLY_DETECTED
=
'newly_detected'
NEWLY_DETECTED_STATE
=
{
NEWLY_DETECTED
.
to_sym
=>
0
}.
freeze
APPROVAL_VULNERABILITY_STATES
=
::
Enums
::
Vulnerability
.
vulnerability_states
.
merge
(
NEWLY_DETECTED_STATE
).
freeze
belongs_to
:project
belongs_to
:project
has_and_belongs_to_many
:protected_branches
has_and_belongs_to_many
:protected_branches
...
@@ -37,6 +40,8 @@ class ApprovalProjectRule < ApplicationRecord
...
@@ -37,6 +40,8 @@ class ApprovalProjectRule < ApplicationRecord
validates
:severity_levels
,
inclusion:
{
in:
::
Enums
::
Vulnerability
.
severity_levels
.
keys
}
validates
:severity_levels
,
inclusion:
{
in:
::
Enums
::
Vulnerability
.
severity_levels
.
keys
}
default_value_for
:severity_levels
,
allows_nil:
false
,
value:
DEFAULT_SEVERITIES
default_value_for
:severity_levels
,
allows_nil:
false
,
value:
DEFAULT_SEVERITIES
validates
:vulnerability_states
,
inclusion:
{
in:
APPROVAL_VULNERABILITY_STATES
.
keys
}
def
applies_to_branch?
(
branch
)
def
applies_to_branch?
(
branch
)
return
true
if
protected_branches
.
empty?
return
true
if
protected_branches
.
empty?
...
@@ -65,6 +70,14 @@ class ApprovalProjectRule < ApplicationRecord
...
@@ -65,6 +70,14 @@ class ApprovalProjectRule < ApplicationRecord
push_audit_event
(
"Removed
#{
model
.
class
.
name
}
#{
model
.
name
}
from approval group on
#{
self
.
name
}
rule"
)
push_audit_event
(
"Removed
#{
model
.
class
.
name
}
#{
model
.
name
}
from approval group on
#{
self
.
name
}
rule"
)
end
end
def
vulnerability_states_for_branch
(
branch
=
project
.
default_branch
)
if
applies_to_branch?
(
branch
)
self
.
vulnerability_states
else
self
.
vulnerability_states
.
select
{
|
state
|
NEWLY_DETECTED
==
state
}
end
end
private
private
def
report_approver_attributes
def
report_approver_attributes
...
...
ee/app/models/ci/minutes/namespace_monthly_usage.rb
View file @
0854b021
...
@@ -27,13 +27,14 @@ module Ci
...
@@ -27,13 +27,14 @@ module Ci
current_month
.
safe_find_or_create_by
(
namespace_id:
namespace_id
)
current_month
.
safe_find_or_create_by
(
namespace_id:
namespace_id
)
end
end
def
self
.
increase_usage
(
usage
,
amount
)
def
self
.
increase_usage
(
usage
,
increments
)
return
unless
amount
>
0
increment_params
=
increments
.
select
{
|
_attribute
,
value
|
value
>
0
}
return
if
increment_params
.
empty?
# The use of `update_counters` ensures we do a SQL update rather than
# The use of `update_counters` ensures we do a SQL update rather than
# incrementing the counter for the object in memory and then save it.
# incrementing the counter for the object in memory and then save it.
# This is better for concurrent updates.
# This is better for concurrent updates.
update_counters
(
usage
,
amount_used:
amount
)
update_counters
(
usage
,
increment_params
)
end
end
def
self
.
reset_current_usage
(
namespace
)
def
self
.
reset_current_usage
(
namespace
)
...
...
ee/app/models/ci/minutes/project_monthly_usage.rb
View file @
0854b021
...
@@ -30,13 +30,14 @@ module Ci
...
@@ -30,13 +30,14 @@ module Ci
current_month
.
safe_find_or_create_by
(
project_id:
project_id
)
current_month
.
safe_find_or_create_by
(
project_id:
project_id
)
end
end
def
self
.
increase_usage
(
usage
,
amount
)
def
self
.
increase_usage
(
usage
,
increments
)
return
unless
amount
>
0
increment_params
=
increments
.
select
{
|
_attribute
,
value
|
value
>
0
}
return
if
increment_params
.
empty?
# The use of `update_counters` ensures we do a SQL update rather than
# The use of `update_counters` ensures we do a SQL update rather than
# incrementing the counter for the object in memory and then save it.
# incrementing the counter for the object in memory and then save it.
# This is better for concurrent updates.
# This is better for concurrent updates.
update_counters
(
usage
,
amount_used:
amount
)
update_counters
(
usage
,
increment_params
)
end
end
end
end
end
end
...
...
ee/app/models/ee/vulnerability.rb
View file @
0854b021
...
@@ -57,9 +57,7 @@ module EE
...
@@ -57,9 +57,7 @@ module EE
has_many
:notes
,
as: :noteable
,
dependent: :delete_all
# rubocop:disable Cop/ActiveRecordDependent
has_many
:notes
,
as: :noteable
,
dependent: :delete_all
# rubocop:disable Cop/ActiveRecordDependent
has_many
:user_mentions
,
class_name:
'VulnerabilityUserMention'
has_many
:user_mentions
,
class_name:
'VulnerabilityUserMention'
# keep the order of the values in the state enum, it is used in state_order method to properly order vulnerabilities based on state
enum
state:
::
Enums
::
Vulnerability
.
vulnerability_states
# remember to recreate index_vulnerabilities_on_state_case_id index when you update or extend this enum
enum
state:
{
detected:
1
,
confirmed:
4
,
resolved:
3
,
dismissed:
2
}
enum
severity:
::
Enums
::
Vulnerability
.
severity_levels
,
_prefix: :severity
enum
severity:
::
Enums
::
Vulnerability
.
severity_levels
,
_prefix: :severity
enum
confidence:
::
Enums
::
Vulnerability
.
confidence_levels
,
_prefix: :confidence
enum
confidence:
::
Enums
::
Vulnerability
.
confidence_levels
,
_prefix: :confidence
enum
report_type:
::
Enums
::
Vulnerability
.
report_types
enum
report_type:
::
Enums
::
Vulnerability
.
report_types
...
@@ -74,6 +72,7 @@ module EE
...
@@ -74,6 +72,7 @@ module EE
scope
:with_author_and_project
,
->
{
includes
(
:author
,
:project
)
}
scope
:with_author_and_project
,
->
{
includes
(
:author
,
:project
)
}
scope
:with_findings
,
->
{
includes
(
:findings
)
}
scope
:with_findings
,
->
{
includes
(
:findings
)
}
scope
:with_findings_by_uuid_and_state
,
->
(
uuid
,
state
)
{
with_findings
.
where
(
findings:
{
uuid:
uuid
},
state:
state
)
}
scope
:with_findings_and_scanner
,
->
{
includes
(
findings: :scanner
)
}
scope
:with_findings_and_scanner
,
->
{
includes
(
findings: :scanner
)
}
scope
:with_findings_scanner_and_identifiers
,
->
{
includes
(
findings:
[
:scanner
,
:identifiers
,
finding_identifiers: :identifier
])
}
scope
:with_findings_scanner_and_identifiers
,
->
{
includes
(
findings:
[
:scanner
,
:identifiers
,
finding_identifiers: :identifier
])
}
scope
:with_created_issue_links_and_issues
,
->
{
includes
(
created_issue_links: :issue
)
}
scope
:with_created_issue_links_and_issues
,
->
{
includes
(
created_issue_links: :issue
)
}
...
...
ee/app/services/ci/minutes/update_project_and_namespace_usage_service.rb
View file @
0854b021
...
@@ -16,10 +16,10 @@ module Ci
...
@@ -16,10 +16,10 @@ module Ci
end
end
# Updates the project and namespace usage based on the passed consumption amount
# Updates the project and namespace usage based on the passed consumption amount
def
execute
(
consumption
)
def
execute
(
consumption
,
duration
=
nil
)
legacy_track_usage_of_monthly_minutes
(
consumption
)
legacy_track_usage_of_monthly_minutes
(
consumption
)
ensure_idempotency
{
track_
usage_of_monthly_minutes
(
consumption
)
}
ensure_idempotency
{
track_
monthly_usage
(
consumption
,
duration
.
to_i
)
}
send_minutes_email_notification
send_minutes_email_notification
end
end
...
@@ -53,14 +53,23 @@ module Ci
...
@@ -53,14 +53,23 @@ module Ci
update_legacy_namespace_minutes
(
consumption_in_seconds
)
update_legacy_namespace_minutes
(
consumption_in_seconds
)
end
end
def
track_
usage_of_monthly_minutes
(
consump
tion
)
def
track_
monthly_usage
(
consumption
,
dura
tion
)
# preload minutes usage data outside of transaction
# preload minutes usage data outside of transaction
project_usage
project_usage
namespace_usage
namespace_usage
::
Ci
::
Minutes
::
NamespaceMonthlyUsage
.
transaction
do
::
Ci
::
Minutes
::
NamespaceMonthlyUsage
.
transaction
do
::
Ci
::
Minutes
::
NamespaceMonthlyUsage
.
increase_usage
(
namespace_usage
,
consumption
)
if
namespace_usage
if
namespace_usage
::
Ci
::
Minutes
::
ProjectMonthlyUsage
.
increase_usage
(
project_usage
,
consumption
)
if
project_usage
::
Ci
::
Minutes
::
NamespaceMonthlyUsage
.
increase_usage
(
namespace_usage
,
amount_used:
consumption
,
shared_runners_duration:
duration
)
end
if
project_usage
::
Ci
::
Minutes
::
ProjectMonthlyUsage
.
increase_usage
(
project_usage
,
amount_used:
consumption
,
shared_runners_duration:
duration
)
end
end
end
end
end
...
...
ee/app/services/ci/sync_reports_to_approval_rules_service.rb
View file @
0854b021
...
@@ -23,7 +23,7 @@ module Ci
...
@@ -23,7 +23,7 @@ module Ci
log_error
(
payload
)
log_error
(
payload
)
error
(
"Failed to update approval rules"
)
error
(
"Failed to update approval rules"
)
ensure
ensure
[
:project_rule_vulnerabilities_allowed
,
:project_rule_scanners
,
:project_rule_severity_levels
,
:project_vulnerability_report
,
:reports
].
each
do
|
memoization
|
[
:project_rule_vulnerabilities_allowed
,
:project_rule_scanners
,
:project_rule_severity_levels
,
:project_vulnerability_report
,
:reports
,
:project_rule_vulnerability_states
].
each
do
|
memoization
|
clear_memoization
(
memoization
)
clear_memoization
(
memoization
)
end
end
end
end
...
@@ -86,7 +86,7 @@ module Ci
...
@@ -86,7 +86,7 @@ module Ci
def
merge_requests_approved_security_reports
def
merge_requests_approved_security_reports
pipeline
.
merge_requests_as_head_pipeline
.
reject
do
|
merge_request
|
pipeline
.
merge_requests_as_head_pipeline
.
reject
do
|
merge_request
|
reports
.
present?
&&
reports
.
violates_default_policy_against?
(
merge_request
.
base_pipeline
&
.
security_reports
,
project_rule_vulnerabilities_allowed
,
project_rule_severity_levels
)
reports
.
present?
&&
reports
.
violates_default_policy_against?
(
merge_request
.
base_pipeline
&
.
security_reports
,
project_rule_vulnerabilities_allowed
,
project_rule_severity_levels
,
project_rule_vulnerability_states
)
end
end
end
end
...
@@ -102,6 +102,12 @@ module Ci
...
@@ -102,6 +102,12 @@ module Ci
end
end
end
end
def
project_rule_vulnerability_states
strong_memoize
(
:project_rule_vulnerability_states
)
do
project_vulnerability_report
&
.
vulnerability_states_for_branch
end
end
def
project_vulnerability_report
def
project_vulnerability_report
strong_memoize
(
:project_vulnerability_report
)
do
strong_memoize
(
:project_vulnerability_report
)
do
pipeline
.
project
.
vulnerability_report_rule
pipeline
.
project
.
vulnerability_report_rule
...
...
ee/app/workers/ci/minutes/update_project_and_namespace_usage_worker.rb
View file @
0854b021
...
@@ -13,10 +13,10 @@ module Ci
...
@@ -13,10 +13,10 @@ module Ci
# used by the service object.
# used by the service object.
sidekiq_options
retry:
3
sidekiq_options
retry:
3
def
perform
(
consumption
,
project_id
,
namespace_id
,
build_id
)
def
perform
(
consumption
,
project_id
,
namespace_id
,
build_id
,
params
=
{}
)
::
Ci
::
Minutes
::
UpdateProjectAndNamespaceUsageService
::
Ci
::
Minutes
::
UpdateProjectAndNamespaceUsageService
.
new
(
project_id
,
namespace_id
,
build_id
)
.
new
(
project_id
,
namespace_id
,
build_id
)
.
execute
(
consumption
)
.
execute
(
consumption
,
params
[
:duration
].
to_i
)
end
end
end
end
end
end
...
...
ee/app/workers/project_import_schedule_worker.rb
View file @
0854b021
...
@@ -12,6 +12,7 @@ class ProjectImportScheduleWorker
...
@@ -12,6 +12,7 @@ class ProjectImportScheduleWorker
feature_category
:source_code_management
feature_category
:source_code_management
sidekiq_options
retry:
false
sidekiq_options
retry:
false
loggable_arguments
1
# For the job waiter key
loggable_arguments
1
# For the job waiter key
log_bulk_perform_async!
# UpdateAllMirrorsWorker depends on the queue size of this worker:
# UpdateAllMirrorsWorker depends on the queue size of this worker:
# https://gitlab.com/gitlab-org/gitlab/-/issues/340630
# https://gitlab.com/gitlab-org/gitlab/-/issues/340630
...
...
ee/config/metrics/license/20210204124831_license_md5.yml
View file @
0854b021
...
@@ -9,13 +9,15 @@ value_type: string
...
@@ -9,13 +9,15 @@ value_type: string
status
:
active
status
:
active
time_frame
:
none
time_frame
:
none
data_source
:
license
data_source
:
license
instrumentation_class
:
LicenseMdFiveMetric
instrumentation_class
:
LicenseMetric
options
:
attribute
:
md5
data_category
:
standard
data_category
:
standard
distribution
:
distribution
:
-
ee
-
ee
tier
:
tier
:
-
premium
-
premium
-
ultimate
-
ultimate
introduced_by_url
:
https://gitlab.com/gitlab-org/gitlab/-/merge_requests/557
introduced_by_url
:
https://gitlab.com/gitlab-org/gitlab/-/merge_requests/557
performance_indicator_type
:
[]
performance_indicator_type
:
[]
milestone
:
"
<13.9"
milestone
:
"
<13.9"
ee/config/metrics/license/20210204124833_license_id.yml
View file @
0854b021
...
@@ -10,6 +10,9 @@ status: active
...
@@ -10,6 +10,9 @@ status: active
time_frame
:
none
time_frame
:
none
data_source
:
license
data_source
:
license
data_category
:
subscription
data_category
:
subscription
instrumentation_class
:
LicenseMetric
options
:
attribute
:
id
distribution
:
distribution
:
-
ee
-
ee
tier
:
tier
:
...
...
ee/config/metrics/license/20210204124843_license_user_count.yml
View file @
0854b021
...
@@ -10,6 +10,9 @@ status: active
...
@@ -10,6 +10,9 @@ status: active
time_frame
:
none
time_frame
:
none
data_source
:
license
data_source
:
license
data_category
:
subscription
data_category
:
subscription
instrumentation_class
:
LicenseMetric
options
:
attribute
:
user_count
distribution
:
distribution
:
-
ee
-
ee
tier
:
tier
:
...
...
ee/config/metrics/license/20210204124845_license_starts_at.yml
View file @
0854b021
...
@@ -10,6 +10,9 @@ status: active
...
@@ -10,6 +10,9 @@ status: active
time_frame
:
none
time_frame
:
none
data_source
:
license
data_source
:
license
data_category
:
subscription
data_category
:
subscription
instrumentation_class
:
LicenseMetric
options
:
attribute
:
starts_at
distribution
:
distribution
:
-
ee
-
ee
tier
:
tier
:
...
...
ee/config/metrics/license/20210204124847_license_expires_at.yml
View file @
0854b021
...
@@ -10,6 +10,9 @@ status: active
...
@@ -10,6 +10,9 @@ status: active
data_category
:
subscription
data_category
:
subscription
time_frame
:
none
time_frame
:
none
data_source
:
license
data_source
:
license
instrumentation_class
:
LicenseMetric
options
:
attribute
:
expires_at
distribution
:
distribution
:
-
ee
-
ee
tier
:
tier
:
...
...
ee/config/metrics/license/20210204124849_license_plan.yml
View file @
0854b021
...
@@ -10,6 +10,9 @@ status: active
...
@@ -10,6 +10,9 @@ status: active
time_frame
:
none
time_frame
:
none
data_source
:
license
data_source
:
license
data_category
:
subscription
data_category
:
subscription
instrumentation_class
:
LicenseMetric
options
:
attribute
:
plan
distribution
:
distribution
:
-
ee
-
ee
tier
:
tier
:
...
...
ee/config/metrics/license/20210204124851_license_trial.yml
View file @
0854b021
...
@@ -10,6 +10,9 @@ status: active
...
@@ -10,6 +10,9 @@ status: active
time_frame
:
none
time_frame
:
none
data_source
:
license
data_source
:
license
data_category
:
subscription
data_category
:
subscription
instrumentation_class
:
LicenseMetric
options
:
attribute
:
trial
distribution
:
distribution
:
-
ee
-
ee
tier
:
tier
:
...
...
ee/config/metrics/license/20210204124852_license_subscription_id.yml
View file @
0854b021
...
@@ -9,7 +9,9 @@ value_type: string
...
@@ -9,7 +9,9 @@ value_type: string
status
:
active
status
:
active
time_frame
:
none
time_frame
:
none
data_source
:
license
data_source
:
license
instrumentation_class
:
ZuoraSubscriptionIdMetric
instrumentation_class
:
LicenseMetric
options
:
attribute
:
subscription_id
data_category
:
standard
data_category
:
standard
distribution
:
distribution
:
-
ee
-
ee
...
...
ee/config/metrics/license/20210204124926_license_trial_ends_on.yml
View file @
0854b021
...
@@ -10,6 +10,9 @@ status: active
...
@@ -10,6 +10,9 @@ status: active
time_frame
:
none
time_frame
:
none
data_source
:
database
data_source
:
database
data_category
:
subscription
data_category
:
subscription
instrumentation_class
:
LicenseMetric
options
:
attribute
:
trial_ends_on
distribution
:
distribution
:
-
ee
-
ee
tier
:
tier
:
...
...
ee/lib/api/helpers/project_approval_rules_helpers.rb
View file @
0854b021
...
@@ -16,6 +16,7 @@ module API
...
@@ -16,6 +16,7 @@ module API
optional
:vulnerabilities_allowed
,
type:
Integer
,
desc:
'The number of vulnerabilities allowed for this rule'
optional
:vulnerabilities_allowed
,
type:
Integer
,
desc:
'The number of vulnerabilities allowed for this rule'
optional
:severity_levels
,
type:
Array
[
String
],
desc:
'The security levels to be considered by the approval rule'
optional
:severity_levels
,
type:
Array
[
String
],
desc:
'The security levels to be considered by the approval rule'
optional
:report_type
,
type:
String
,
desc:
'The type of the report required when rule type equals to report_approver'
optional
:report_type
,
type:
String
,
desc:
'The type of the report required when rule type equals to report_approver'
optional
:vulnerability_states
,
type:
Array
[
String
],
desc:
'The vulnerability states to be considered by the approval rule'
end
end
params
:update_project_approval_rule
do
params
:update_project_approval_rule
do
...
@@ -29,6 +30,7 @@ module API
...
@@ -29,6 +30,7 @@ module API
optional
:scanners
,
type:
Array
[
String
],
desc:
'The security scanners to be considered by the approval rule'
optional
:scanners
,
type:
Array
[
String
],
desc:
'The security scanners to be considered by the approval rule'
optional
:vulnerabilities_allowed
,
type:
Integer
,
desc:
'The number of vulnerabilities allowed for this rule'
optional
:vulnerabilities_allowed
,
type:
Integer
,
desc:
'The number of vulnerabilities allowed for this rule'
optional
:severity_levels
,
type:
Array
[
String
],
desc:
'The security levels to be considered by the approval rule'
optional
:severity_levels
,
type:
Array
[
String
],
desc:
'The security levels to be considered by the approval rule'
optional
:vulnerability_states
,
type:
Array
[
String
],
desc:
'The vulnerability states to be considered by the approval rule'
end
end
params
:delete_project_approval_rule
do
params
:delete_project_approval_rule
do
...
...
ee/lib/ee/api/entities/project_approval_setting_rule.rb
View file @
0854b021
...
@@ -12,6 +12,7 @@ module EE
...
@@ -12,6 +12,7 @@ module EE
expose
:scanners
,
override:
true
expose
:scanners
,
override:
true
expose
:vulnerabilities_allowed
,
override:
true
expose
:vulnerabilities_allowed
,
override:
true
expose
:severity_levels
,
override:
true
expose
:severity_levels
,
override:
true
expose
:vulnerability_states
,
override:
true
end
end
end
end
end
end
...
...
ee/lib/ee/gitlab/ci/reports/security/reports.rb
0 → 100644
View file @
0854b021
# frozen_string_literal: true
module
EE
module
Gitlab
module
Ci
module
Reports
module
Security
module
Reports
extend
::
Gitlab
::
Utils
::
Override
private
override
:unsafe_findings_count
def
unsafe_findings_count
(
target_reports
,
severity_levels
,
vulnerability_states
)
pipeline_uuids
=
unsafe_findings_uuids
(
severity_levels
)
pipeline_count
=
count_by_uuid
(
pipeline_uuids
,
vulnerability_states
)
new_uuids
=
pipeline_uuids
-
target_reports
&
.
unsafe_findings_uuids
(
severity_levels
).
to_a
if
vulnerability_states
.
include?
(
ApprovalProjectRule
::
NEWLY_DETECTED
)
pipeline_count
+=
new_uuids
.
count
end
pipeline_count
end
def
count_by_uuid
(
uuids
,
states
)
pipeline
.
project
.
vulnerabilities
.
with_findings_by_uuid_and_state
(
uuids
,
states
.
reject
{
|
state
|
ApprovalProjectRule
::
NEWLY_DETECTED
==
state
}).
count
end
end
end
end
end
end
end
ee/lib/ee/gitlab/usage_data.rb
View file @
0854b021
...
@@ -72,7 +72,7 @@ module EE
...
@@ -72,7 +72,7 @@ module EE
def
features_usage_data_ee
def
features_usage_data_ee
{
{
elasticsearch_enabled:
alt_usage_data
(
fallback:
nil
)
{
::
Gitlab
::
CurrentSettings
.
elasticsearch_search?
},
elasticsearch_enabled:
alt_usage_data
(
fallback:
nil
)
{
::
Gitlab
::
CurrentSettings
.
elasticsearch_search?
},
license_trial_ends_on:
a
lt_usage_data
(
fallback:
nil
)
{
License
.
trial_ends_on
}
,
license_trial_ends_on:
a
dd_metric
(
"LicenseMetric"
,
options:
{
attribute:
"trial_ends_on"
})
,
geo_enabled:
alt_usage_data
(
fallback:
nil
)
{
::
Gitlab
::
Geo
.
enabled?
},
geo_enabled:
alt_usage_data
(
fallback:
nil
)
{
::
Gitlab
::
Geo
.
enabled?
},
user_cap_feature_enabled:
add_metric
(
'UserCapSettingEnabledMetric'
,
time_frame:
'none'
)
user_cap_feature_enabled:
add_metric
(
'UserCapSettingEnabledMetric'
,
time_frame:
'none'
)
}
}
...
@@ -90,7 +90,7 @@ module EE
...
@@ -90,7 +90,7 @@ module EE
end
end
if
license
if
license
usage_data
[
:license_md5
]
=
add_metric
(
"LicenseM
dFiveMetric"
)
usage_data
[
:license_md5
]
=
add_metric
(
"LicenseM
etric"
,
options:
{
attribute:
'md5'
}
)
usage_data
[
:license_id
]
=
license
.
license_id
usage_data
[
:license_id
]
=
license
.
license_id
# rubocop: disable UsageData/LargeTable
# rubocop: disable UsageData/LargeTable
usage_data
[
:historical_max_users
]
=
add_metric
(
"HistoricalMaxUsersMetric"
)
usage_data
[
:historical_max_users
]
=
add_metric
(
"HistoricalMaxUsersMetric"
)
...
@@ -103,7 +103,7 @@ module EE
...
@@ -103,7 +103,7 @@ module EE
usage_data
[
:license_plan
]
=
license
.
plan
usage_data
[
:license_plan
]
=
license
.
plan
usage_data
[
:license_add_ons
]
=
license
.
add_ons
usage_data
[
:license_add_ons
]
=
license
.
add_ons
usage_data
[
:license_trial
]
=
license
.
trial?
usage_data
[
:license_trial
]
=
license
.
trial?
usage_data
[
:license_subscription_id
]
=
alt_usage_data
(
fallback:
nil
)
{
license
.
subscription_id
}
usage_data
[
:license_subscription_id
]
=
license
.
subscription_id
end
end
usage_data
usage_data
...
...
ee/lib/gitlab/usage/metrics/instrumentations/license_md_five_metric.rb
deleted
100644 → 0
View file @
b84cd406
# frozen_string_literal: true
module
Gitlab
module
Usage
module
Metrics
module
Instrumentations
class
LicenseMdFiveMetric
<
::
Gitlab
::
Usage
::
Metrics
::
Instrumentations
::
GenericMetric
value
do
::
License
.
current
.
md5
end
end
end
end
end
end
ee/lib/gitlab/usage/metrics/instrumentations/license_metric.rb
0 → 100644
View file @
0854b021
# frozen_string_literal: true
module
Gitlab
module
Usage
module
Metrics
module
Instrumentations
class
LicenseMetric
<
GenericMetric
# Usage example
#
# In metric YAML defintion
# instrumentation_class: LicenseMetric
# options:
# attribute: md5
# end
ALLOWED_ATTRIBUTES
=
%w(md5
id
plan
trial
starts_at
expires_at
user_count
trial_ends_on
subscription_id)
.
freeze
def
initialize
(
time_frame
:,
options:
{})
super
raise
ArgumentError
,
"License options attribute are required"
unless
license_attribute
.
present?
raise
ArgumentError
,
"Attribute:
#{
license_attribute
}
it not allowed"
unless
license_attribute
.
in?
(
ALLOWED_ATTRIBUTES
)
end
def
value
return
::
License
.
trial_ends_on
if
license_attribute
==
"trial_ends_on"
alt_usage_data
(
fallback:
nil
)
do
# license_attribute is checked in the constructor, so it's safe
::
License
.
current
.
send
(
license_attribute
)
# rubocop: disable GitlabSecurity/PublicSend
end
end
private
def
license_attribute
options
[
:attribute
]
end
end
end
end
end
end
ee/lib/gitlab/usage/metrics/instrumentations/zuora_subscription_id_metric.rb
deleted
100644 → 0
View file @
b84cd406
# frozen_string_literal: true
module
Gitlab
module
Usage
module
Metrics
module
Instrumentations
class
ZuoraSubscriptionIdMetric
<
::
Gitlab
::
Usage
::
Metrics
::
Instrumentations
::
GenericMetric
value
do
::
License
.
current
.
subscription_id
end
end
end
end
end
end
ee/spec/fixtures/api/schemas/public_api/v4/project_approval_setting.json
View file @
0854b021
...
@@ -46,6 +46,12 @@
...
@@ -46,6 +46,12 @@
"items"
:
{
"items"
:
{
"type"
:
"string"
"type"
:
"string"
}
}
},
"vulnerability_states"
:{
"type"
:
"array"
,
"items"
:
{
"type"
:
"string"
}
}
}
},
},
"additionalProperties"
:
false
"additionalProperties"
:
false
...
...
ee/spec/frontend/approvals/components/rule_form_spec.js
View file @
0854b021
import
{
GlFormGroup
,
GlFormInput
,
GlTruncate
}
from
'
@gitlab/ui
'
;
import
{
Gl
Dropdown
,
Gl
FormGroup
,
GlFormInput
,
GlTruncate
}
from
'
@gitlab/ui
'
;
import
{
shallowMount
}
from
'
@vue/test-utils
'
;
import
{
shallowMount
}
from
'
@vue/test-utils
'
;
import
Vue
,
{
nextTick
}
from
'
vue
'
;
import
Vue
,
{
nextTick
}
from
'
vue
'
;
import
Vuex
from
'
vuex
'
;
import
Vuex
from
'
vuex
'
;
...
@@ -13,6 +13,8 @@ import {
...
@@ -13,6 +13,8 @@ import {
TYPE_GROUP
,
TYPE_GROUP
,
TYPE_HIDDEN_GROUPS
,
TYPE_HIDDEN_GROUPS
,
VULNERABILITY_CHECK_NAME
,
VULNERABILITY_CHECK_NAME
,
APPROVAL_VULNERABILITY_STATES
,
APPROVAL_DIALOG_I18N
,
}
from
'
ee/approvals/constants
'
;
}
from
'
ee/approvals/constants
'
;
import
{
createStoreOptions
}
from
'
ee/approvals/stores
'
;
import
{
createStoreOptions
}
from
'
ee/approvals/stores
'
;
import
projectSettingsModule
from
'
ee/approvals/stores/modules/project_settings
'
;
import
projectSettingsModule
from
'
ee/approvals/stores/modules/project_settings
'
;
...
@@ -21,28 +23,14 @@ import ProtectedBranchesSelector from 'ee/vue_shared/components/branches_selecto
...
@@ -21,28 +23,14 @@ import ProtectedBranchesSelector from 'ee/vue_shared/components/branches_selecto
import
{
stubComponent
}
from
'
helpers/stub_component
'
;
import
{
stubComponent
}
from
'
helpers/stub_component
'
;
import
{
extendedWrapper
}
from
'
helpers/vue_test_utils_helper
'
;
import
{
extendedWrapper
}
from
'
helpers/vue_test_utils_helper
'
;
import
waitForPromises
from
'
helpers/wait_for_promises
'
;
import
waitForPromises
from
'
helpers/wait_for_promises
'
;
import
{
TEST_RULE
,
TEST_RULE_VULNERABILITY_CHECK
,
TEST_PROTECTED_BRANCHES
,
TEST_RULE_WITH_PROTECTED_BRANCHES
,
}
from
'
../mocks
'
;
const
TEST_PROJECT_ID
=
'
7
'
;
const
TEST_PROJECT_ID
=
'
7
'
;
const
TEST_RULE
=
{
id
:
10
,
name
:
'
QA
'
,
approvalsRequired
:
2
,
users
:
[{
id
:
1
},
{
id
:
2
},
{
id
:
3
}],
groups
:
[{
id
:
1
},
{
id
:
2
}],
};
const
TEST_PROTECTED_BRANCHES
=
[{
id
:
2
},
{
id
:
3
},
{
id
:
4
}];
const
TEST_RULE_WITH_PROTECTED_BRANCHES
=
{
...
TEST_RULE
,
protectedBranches
:
TEST_PROTECTED_BRANCHES
,
};
const
TEST_RULE_VULNERABILITY_CHECK
=
{
...
TEST_RULE
,
id
:
null
,
name
:
VULNERABILITY_CHECK_NAME
,
scanners
:
[
'
sast
'
,
'
dast
'
],
vulnerabilitiesAllowed
:
0
,
severityLevels
:
[
'
high
'
],
};
const
TEST_APPROVERS
=
[{
id
:
7
,
type
:
TYPE_USER
}];
const
TEST_APPROVERS
=
[{
id
:
7
,
type
:
TYPE_USER
}];
const
TEST_APPROVALS_REQUIRED
=
3
;
const
TEST_APPROVALS_REQUIRED
=
3
;
const
TEST_FALLBACK_RULE
=
{
const
TEST_FALLBACK_RULE
=
{
...
@@ -101,6 +89,9 @@ describe('EE Approvals RuleForm', () => {
...
@@ -101,6 +89,9 @@ describe('EE Approvals RuleForm', () => {
const
findScannersGroup
=
()
=>
wrapper
.
findByTestId
(
'
scanners-group
'
);
const
findScannersGroup
=
()
=>
wrapper
.
findByTestId
(
'
scanners-group
'
);
const
findVulnerabilityFormGroup
=
()
=>
wrapper
.
findByTestId
(
'
vulnerability-amount-group
'
);
const
findVulnerabilityFormGroup
=
()
=>
wrapper
.
findByTestId
(
'
vulnerability-amount-group
'
);
const
findSeverityLevelsGroup
=
()
=>
wrapper
.
findByTestId
(
'
severity-levels-group
'
);
const
findSeverityLevelsGroup
=
()
=>
wrapper
.
findByTestId
(
'
severity-levels-group
'
);
const
findVulnerabilityStatesGroup
=
()
=>
wrapper
.
findByTestId
(
'
vulnerability-states-group
'
);
const
findVulnerabilityStatesDropdown
=
()
=>
findVulnerabilityStatesGroup
().
findComponent
(
GlDropdown
);
const
inputsAreValid
=
(
inputs
)
=>
inputs
.
every
((
x
)
=>
x
.
props
(
'
state
'
));
const
inputsAreValid
=
(
inputs
)
=>
inputs
.
every
((
x
)
=>
x
.
props
(
'
state
'
));
...
@@ -207,6 +198,7 @@ describe('EE Approvals RuleForm', () => {
...
@@ -207,6 +198,7 @@ describe('EE Approvals RuleForm', () => {
scanners
:
[],
scanners
:
[],
severityLevels
:
[],
severityLevels
:
[],
protectedBranchIds
:
branches
.
map
((
x
)
=>
x
.
id
),
protectedBranchIds
:
branches
.
map
((
x
)
=>
x
.
id
),
vulnerabilityStates
:
[],
};
};
await
findNameInput
().
vm
.
$emit
(
'
input
'
,
expected
.
name
);
await
findNameInput
().
vm
.
$emit
(
'
input
'
,
expected
.
name
);
...
@@ -287,6 +279,7 @@ describe('EE Approvals RuleForm', () => {
...
@@ -287,6 +279,7 @@ describe('EE Approvals RuleForm', () => {
scanners
:
[],
scanners
:
[],
severityLevels
:
[],
severityLevels
:
[],
protectedBranchIds
:
branches
.
map
((
x
)
=>
x
.
id
),
protectedBranchIds
:
branches
.
map
((
x
)
=>
x
.
id
),
vulnerabilityStates
:
[],
};
};
beforeEach
(
async
()
=>
{
beforeEach
(
async
()
=>
{
...
@@ -368,6 +361,7 @@ describe('EE Approvals RuleForm', () => {
...
@@ -368,6 +361,7 @@ describe('EE Approvals RuleForm', () => {
scanners
:
[],
scanners
:
[],
severityLevels
:
[],
severityLevels
:
[],
protectedBranchIds
:
[],
protectedBranchIds
:
[],
vulnerabilityStates
:
[],
};
};
it
(
'
on submit, puts rule
'
,
async
()
=>
{
it
(
'
on submit, puts rule
'
,
async
()
=>
{
...
@@ -720,6 +714,95 @@ describe('EE Approvals RuleForm', () => {
...
@@ -720,6 +714,95 @@ describe('EE Approvals RuleForm', () => {
);
);
});
});
});
});
describe
(
'
without any vulnerability state selected
'
,
()
=>
{
beforeEach
(()
=>
{
createComponent
({
initRule
:
{
...
TEST_RULE_VULNERABILITY_CHECK
,
vulnerabilityStates
:
[],
},
});
findForm
().
trigger
(
'
submit
'
);
});
it
(
'
does not dispatch the action on submit
'
,
()
=>
{
expect
(
actions
.
postRule
).
not
.
toHaveBeenCalled
();
});
it
(
'
changes vulnerability states dropdown text to select vulnerability states
'
,
()
=>
{
expect
(
findVulnerabilityStatesDropdown
().
props
(
'
text
'
)).
toBe
(
APPROVAL_DIALOG_I18N
.
form
.
vulnerabilityStatesSelectLabel
,
);
});
it
(
'
shows error message in regards to vulnerability states selection
'
,
()
=>
{
expect
(
findVulnerabilityStatesGroup
().
props
(
'
invalidFeedback
'
)).
toBe
(
APPROVAL_DIALOG_I18N
.
validations
.
vulnerabilityStatesRequired
,
);
});
});
describe
(
'
with one vulnerability state selected
'
,
()
=>
{
beforeEach
(()
=>
{
createComponent
({
initRule
:
{
...
TEST_RULE_VULNERABILITY_CHECK
,
vulnerabilityStates
:
[
'
newly_detected
'
],
},
});
findForm
().
trigger
(
'
submit
'
);
});
it
(
'
dispatches the action on submit
'
,
()
=>
{
expect
(
actions
.
postRule
).
toHaveBeenCalledWith
(
expect
.
anything
(),
expect
.
objectContaining
({
vulnerabilityStates
:
TEST_RULE_VULNERABILITY_CHECK
.
vulnerabilityStates
,
}),
);
});
it
(
'
changes vulnerability states dropdown text to its name
'
,
()
=>
{
expect
(
findVulnerabilityStatesDropdown
().
props
(
'
text
'
)).
toBe
(
APPROVAL_VULNERABILITY_STATES
.
newly_detected
,
);
});
});
describe
(
'
with all vulnerability states selected
'
,
()
=>
{
beforeEach
(()
=>
{
createComponent
({
initRule
:
{
...
TEST_RULE_VULNERABILITY_CHECK
,
vulnerabilityStates
:
Object
.
keys
(
APPROVAL_VULNERABILITY_STATES
),
},
});
});
it
(
'
changes vulnerability states dropdown text to all selected
'
,
()
=>
{
expect
(
findVulnerabilityStatesDropdown
().
props
(
'
text
'
)).
toBe
(
APPROVAL_DIALOG_I18N
.
form
.
allVulnerabilityStatesSelectedLabel
,
);
});
});
describe
(
'
with all but one vulnerability state selected
'
,
()
=>
{
beforeEach
(()
=>
{
createComponent
({
initRule
:
{
...
TEST_RULE_VULNERABILITY_CHECK
,
vulnerabilityStates
:
Object
.
keys
(
APPROVAL_VULNERABILITY_STATES
).
splice
(
1
),
},
});
});
it
(
'
changes vulnerability states dropdown text to all selected
'
,
()
=>
{
expect
(
findVulnerabilityStatesDropdown
().
props
(
'
text
'
)).
toBe
(
'
Previously detected +3 more
'
,
);
});
});
});
});
});
});
...
...
ee/spec/frontend/approvals/mocks.js
View file @
0854b021
...
@@ -93,3 +93,28 @@ export const createGroupApprovalsState = (locked = null) => ({
...
@@ -93,3 +93,28 @@ export const createGroupApprovalsState = (locked = null) => ({
},
},
},
},
});
});
export
const
TEST_PROTECTED_BRANCHES
=
[{
id
:
2
},
{
id
:
3
},
{
id
:
4
}];
export
const
TEST_RULE
=
{
id
:
10
,
name
:
'
QA
'
,
approvalsRequired
:
2
,
users
:
[{
id
:
1
},
{
id
:
2
},
{
id
:
3
}],
groups
:
[{
id
:
1
},
{
id
:
2
}],
};
export
const
TEST_RULE_VULNERABILITY_CHECK
=
{
...
TEST_RULE
,
id
:
null
,
name
:
'
Vulnerability-Check
'
,
scanners
:
[
'
sast
'
,
'
dast
'
],
vulnerabilitiesAllowed
:
0
,
severityLevels
:
[
'
high
'
],
vulnerabilityStates
:
[
'
newly_detected
'
],
};
export
const
TEST_RULE_WITH_PROTECTED_BRANCHES
=
{
...
TEST_RULE
,
protectedBranches
:
TEST_PROTECTED_BRANCHES
,
};
ee/spec/lib/ee/gitlab/ci/reports/security/reports_spec.rb
0 → 100644
View file @
0854b021
# frozen_string_literal: true
require
'spec_helper'
RSpec
.
describe
Gitlab
::
Ci
::
Reports
::
Security
::
Reports
do
let_it_be
(
:pipeline
)
{
create
(
:ci_pipeline
)
}
let_it_be
(
:artifact
)
{
create
(
:ci_job_artifact
,
:sast
)
}
let
(
:security_reports
)
{
described_class
.
new
(
pipeline
)
}
describe
"#violates_default_policy_against?"
do
let
(
:high_severity_dast
)
{
build
(
:ci_reports_security_finding
,
severity:
'high'
,
report_type: :dast
)
}
let
(
:vulnerabilities_allowed
)
{
0
}
let
(
:severity_levels
)
{
%w(critical high)
}
let
(
:vulnerability_states
)
{
%w(newly_detected)
}
subject
{
security_reports
.
violates_default_policy_against?
(
target_reports
,
vulnerabilities_allowed
,
severity_levels
,
vulnerability_states
)
}
before
do
security_reports
.
get_report
(
'sast'
,
artifact
).
add_finding
(
high_severity_dast
)
end
context
'when the target_reports is `nil`'
do
let
(
:target_reports
)
{
nil
}
it
{
is_expected
.
to
be
(
true
)
}
context
'with existing vulnerabilities'
do
let!
(
:finding
)
{
create
(
:vulnerabilities_finding
,
:detected
,
report_type: :sast
,
project:
pipeline
.
project
,
uuid:
high_severity_dast
.
uuid
)
}
it
{
is_expected
.
to
be
(
true
)
}
context
'with vulnerability states matching existing vulnerabilities'
do
let
(
:vulnerability_states
)
{
%w(detected)
}
it
{
is_expected
.
to
be
(
true
)
}
end
context
'with vulnerability states not matching existing vulnerabilities'
do
let
(
:vulnerability_states
)
{
%w(resolved)
}
it
{
is_expected
.
to
be
(
false
)
}
end
end
end
context
'when the target_reports is not `nil`'
do
let
(
:target_reports
)
{
described_class
.
new
(
pipeline
)
}
it
{
is_expected
.
to
be
(
true
)
}
context
"when none of the reports have a new unsafe vulnerability"
do
before
do
target_reports
.
get_report
(
'sast'
,
artifact
).
add_finding
(
high_severity_dast
)
end
it
{
is_expected
.
to
be
(
false
)
}
context
'with existing vulnerabilities'
do
let!
(
:finding
)
{
create
(
:vulnerabilities_finding
,
:detected
,
report_type: :sast
,
project:
pipeline
.
project
,
uuid:
high_severity_dast
.
uuid
)
}
it
{
is_expected
.
to
be
(
false
)
}
context
'with vulnerability states matching existing vulnerability'
do
let
(
:vulnerability_states
)
{
%w(detected)
}
it
{
is_expected
.
to
be
(
true
)
}
end
context
'with vulnerability states not matching existing vulnerabilities'
do
let
(
:vulnerability_states
)
{
%w(resolved)
}
it
{
is_expected
.
to
be
(
false
)
}
end
end
end
end
end
end
ee/spec/lib/ee/gitlab/usage_data_spec.rb
View file @
0854b021
...
@@ -187,6 +187,10 @@ RSpec.describe Gitlab::UsageData do
...
@@ -187,6 +187,10 @@ RSpec.describe Gitlab::UsageData do
describe
'.features_usage_data_ee'
do
describe
'.features_usage_data_ee'
do
subject
{
described_class
.
features_usage_data_ee
}
subject
{
described_class
.
features_usage_data_ee
}
before
do
stub_feature_flags
(
usage_data_instrumentation:
false
)
end
it
'gathers feature usage data of EE'
do
it
'gathers feature usage data of EE'
do
expect
(
subject
[
:elasticsearch_enabled
]).
to
eq
(
Gitlab
::
CurrentSettings
.
elasticsearch_search?
)
expect
(
subject
[
:elasticsearch_enabled
]).
to
eq
(
Gitlab
::
CurrentSettings
.
elasticsearch_search?
)
expect
(
subject
[
:geo_enabled
]).
to
eq
(
Gitlab
::
Geo
.
enabled?
)
expect
(
subject
[
:geo_enabled
]).
to
eq
(
Gitlab
::
Geo
.
enabled?
)
...
...
ee/spec/lib/gitlab/usage/metrics/instrumentations/license_md_five_metric_spec.rb
deleted
100644 → 0
View file @
b84cd406
# frozen_string_literal: true
require
'spec_helper'
RSpec
.
describe
Gitlab
::
Usage
::
Metrics
::
Instrumentations
::
LicenseMdFiveMetric
do
it_behaves_like
'a correct instrumented metric value'
,
{
time_frame:
'none'
,
data_source:
'ruby'
}
do
let
(
:expected_value
)
{
Digest
::
MD5
.
hexdigest
(
::
License
.
current
.
data
)
}
end
end
ee/spec/lib/gitlab/usage/metrics/instrumentations/zuora_subscription_id_metric_spec.rb
deleted
100644 → 0
View file @
b84cd406
# frozen_string_literal: true
require
'spec_helper'
RSpec
.
describe
Gitlab
::
Usage
::
Metrics
::
Instrumentations
::
ZuoraSubscriptionIdMetric
do
it_behaves_like
'a correct instrumented metric value'
,
{
time_frame:
'none'
,
data_source:
'ruby'
}
do
let
(
:expected_value
)
{
::
License
.
current
.
subscription_id
}
end
end
ee/spec/models/approval_project_rule_spec.rb
View file @
0854b021
...
@@ -15,6 +15,12 @@ RSpec.describe ApprovalProjectRule do
...
@@ -15,6 +15,12 @@ RSpec.describe ApprovalProjectRule do
expect
(
::
Enums
::
Vulnerability
.
severity_levels
.
keys
).
to
include
(
*
described_class
::
DEFAULT_SEVERITIES
)
expect
(
::
Enums
::
Vulnerability
.
severity_levels
.
keys
).
to
include
(
*
described_class
::
DEFAULT_SEVERITIES
)
end
end
end
end
context
'APPROVAL_VULNERABILITY_STATES'
do
it
'contains all vulnerability states'
do
expect
(
described_class
::
APPROVAL_VULNERABILITY_STATES
).
to
include
(
*::
Enums
::
Vulnerability
.
vulnerability_states
.
keys
)
end
end
end
end
describe
'associations'
do
describe
'associations'
do
...
@@ -177,20 +183,21 @@ RSpec.describe ApprovalProjectRule do
...
@@ -177,20 +183,21 @@ RSpec.describe ApprovalProjectRule do
context
"with a `Vulnerability-Check` rule"
do
context
"with a `Vulnerability-Check` rule"
do
using
RSpec
::
Parameterized
::
TableSyntax
using
RSpec
::
Parameterized
::
TableSyntax
where
(
:is_valid
,
:scanners
,
:vulnerabilities_allowed
,
:severity_levels
)
do
where
(
:is_valid
,
:scanners
,
:vulnerabilities_allowed
,
:severity_levels
,
:vulnerability_states
)
do
true
|
[]
|
0
|
[]
true
|
[]
|
0
|
[]
|
%w(newly_detected)
true
|
%w(dast)
|
1
|
%w(critical high medium)
true
|
%w(dast)
|
1
|
%w(critical high medium)
|
%w(newly_detected resolved)
true
|
%w(dast sast)
|
10
|
%w(critical high)
true
|
%w(dast sast)
|
10
|
%w(critical high)
|
%w(resolved detected)
true
|
%w(dast dast)
|
100
|
%w(critical)
true
|
%w(dast dast)
|
100
|
%w(critical)
|
%w(detected dismissed)
false
|
%w(dast dast)
|
100
|
%w(unknown_severity)
false
|
%w(dast dast)
|
100
|
%w(critical)
|
%w(dismissed unknown)
false
|
%w(dast unknown_scanner)
|
100
|
%w(critical)
false
|
%w(dast dast)
|
100
|
%w(unknown_severity)
|
%w(detected dismissed)
false
|
[
described_class
::
UNSUPPORTED_SCANNER
]
|
100
|
%w(critical)
false
|
%w(dast unknown_scanner)
|
100
|
%w(critical)
|
%w(detected dismissed)
false
|
%w(dast sast)
|
1.1
|
%w(critical)
false
|
[
described_class
::
UNSUPPORTED_SCANNER
]
|
100
|
%w(critical)
|
%w(detected dismissed)
false
|
%w(dast sast)
|
'one'
|
%w(critical)
false
|
%w(dast sast)
|
1.1
|
%w(critical)
|
%w(detected dismissed)
false
|
%w(dast sast)
|
'one'
|
%w(critical)
|
%w(detected dismissed)
end
end
with_them
do
with_them
do
let
(
:vulnerability_check_rule
)
{
build
(
:approval_project_rule
,
:vulnerability
,
scanners:
scanners
,
vulnerabilities_allowed:
vulnerabilities_allowed
,
severity_levels:
severity_levels
)
}
let
(
:vulnerability_check_rule
)
{
build
(
:approval_project_rule
,
:vulnerability
,
scanners:
scanners
,
vulnerabilities_allowed:
vulnerabilities_allowed
,
severity_levels:
severity_levels
,
vulnerability_states:
vulnerability_states
)
}
specify
{
expect
(
vulnerability_check_rule
.
valid?
).
to
be
(
is_valid
)
}
specify
{
expect
(
vulnerability_check_rule
.
valid?
).
to
be
(
is_valid
)
}
end
end
...
@@ -273,5 +280,27 @@ RSpec.describe ApprovalProjectRule do
...
@@ -273,5 +280,27 @@ RSpec.describe ApprovalProjectRule do
it_behaves_like
'auditable'
it_behaves_like
'auditable'
end
end
describe
'#vulnerability_states_for_branch'
do
let
(
:project
)
{
create
(
:project
,
:repository
)
}
let
(
:branch_name
)
{
project
.
default_branch
}
let!
(
:rule
)
{
build
(
:approval_project_rule
,
project:
project
,
protected_branches:
protected_branches
,
vulnerability_states:
%w(newly_detected resolved)
)
}
context
'with protected branch set to any'
do
let
(
:protected_branches
)
{
[]
}
it
'returns all content of vulnerability states'
do
expect
(
rule
.
vulnerability_states_for_branch
).
to
contain_exactly
(
'newly_detected'
,
'resolved'
)
end
end
context
'with protected branch set to a custom branch'
do
let
(
:protected_branches
)
{
[
create
(
:protected_branch
,
project:
project
,
name:
'custom_branch'
)]
}
it
'returns only the content of vulnerability states'
do
expect
(
rule
.
vulnerability_states_for_branch
).
to
contain_exactly
(
'newly_detected'
)
end
end
end
end
end
end
end
ee/spec/models/ci/minutes/namespace_monthly_usage_spec.rb
View file @
0854b021
...
@@ -71,27 +71,7 @@ RSpec.describe Ci::Minutes::NamespaceMonthlyUsage do
...
@@ -71,27 +71,7 @@ RSpec.describe Ci::Minutes::NamespaceMonthlyUsage do
end
end
describe
'.increase_usage'
do
describe
'.increase_usage'
do
subject
{
described_class
.
increase_usage
(
current_usage
,
amount
)
}
it_behaves_like
'CI minutes increase usage'
context
'when amount is greater than 0'
do
let
(
:amount
)
{
10.5
}
it
'updates the current month usage'
do
subject
expect
(
current_usage
.
reload
.
amount_used
).
to
eq
(
110.5
)
end
end
context
'when amount is less or equal to 0'
do
let
(
:amount
)
{
-
2.0
}
it
'does not update the current month usage'
do
subject
expect
(
current_usage
.
reload
.
amount_used
).
to
eq
(
100.0
)
end
end
end
end
describe
'.for_namespace'
do
describe
'.for_namespace'
do
...
...
ee/spec/models/ci/minutes/project_monthly_usage_spec.rb
View file @
0854b021
...
@@ -66,29 +66,13 @@ RSpec.describe Ci::Minutes::ProjectMonthlyUsage do
...
@@ -66,29 +66,13 @@ RSpec.describe Ci::Minutes::ProjectMonthlyUsage do
end
end
describe
'.increase_usage'
do
describe
'.increase_usage'
do
subject
{
described_class
.
increase_usage
(
usage
,
amount
)
}
let_it_be_with_refind
(
:current_usage
)
do
create
(
:ci_project_monthly_usage
,
let
(
:usage
)
{
create
(
:ci_project_monthly_usage
,
project:
project
,
amount_used:
100.0
)
}
project:
project
,
amount_used:
100
)
context
'when amount is greater than 0'
do
let
(
:amount
)
{
10.5
}
it
'updates the current month usage'
do
subject
expect
(
usage
.
reload
.
amount_used
).
to
eq
(
110.5
)
end
end
end
context
'when amount is less or equal to 0'
do
it_behaves_like
'CI minutes increase usage'
let
(
:amount
)
{
-
2.0
}
it
'does not update the current month usage'
do
subject
expect
(
usage
.
reload
.
amount_used
).
to
eq
(
100.0
)
end
end
end
end
describe
'.for_namespace_monthly_usage'
do
describe
'.for_namespace_monthly_usage'
do
...
...
ee/spec/models/ee/vulnerability_spec.rb
View file @
0854b021
...
@@ -826,4 +826,26 @@ RSpec.describe Vulnerability do
...
@@ -826,4 +826,26 @@ RSpec.describe Vulnerability do
)
)
end
end
end
end
describe
'.with_findings_by_uuid_and_state scope'
do
let_it_be
(
:vulnerability
)
{
create
(
:vulnerability
,
state: :detected
)
}
let
(
:uuid
)
{
[
SecureRandom
.
uuid
]
}
subject
{
described_class
.
with_findings_by_uuid_and_state
(
uuid
,
[
"detected"
])
}
it
{
is_expected
.
to
be_empty
}
context
'with findings'
do
let_it_be
(
:finding
)
{
create
(
:vulnerabilities_finding
,
vulnerability:
vulnerability
)
}
it
{
is_expected
.
to
be_empty
}
context
'with matching uuid'
do
let
(
:uuid
)
{
[
finding
.
uuid
]
}
it
{
is_expected
.
to
contain_exactly
(
vulnerability
)
}
end
end
end
end
end
ee/spec/services/ci/minutes/update_project_and_namespace_usage_service_spec.rb
View file @
0854b021
...
@@ -9,13 +9,14 @@ RSpec.describe Ci::Minutes::UpdateProjectAndNamespaceUsageService do
...
@@ -9,13 +9,14 @@ RSpec.describe Ci::Minutes::UpdateProjectAndNamespaceUsageService do
let
(
:namespace
)
{
project
.
namespace
}
let
(
:namespace
)
{
project
.
namespace
}
let
(
:build
)
{
create
(
:ci_build
)
}
let
(
:build
)
{
create
(
:ci_build
)
}
let
(
:consumption_minutes
)
{
120
}
let
(
:consumption_minutes
)
{
120
}
let
(
:duration
)
{
1_000
}
let
(
:consumption_seconds
)
{
consumption_minutes
*
60
}
let
(
:consumption_seconds
)
{
consumption_minutes
*
60
}
let
(
:namespace_amount_used
)
{
Ci
::
Minutes
::
NamespaceMonthlyUsage
.
find_or_create_current
(
namespace_id:
namespace
.
id
).
amount_used
}
let
(
:namespace_amount_used
)
{
Ci
::
Minutes
::
NamespaceMonthlyUsage
.
find_or_create_current
(
namespace_id:
namespace
.
id
).
amount_used
}
let
(
:project_amount_used
)
{
Ci
::
Minutes
::
ProjectMonthlyUsage
.
find_or_create_current
(
project_id:
project
.
id
).
amount_used
}
let
(
:project_amount_used
)
{
Ci
::
Minutes
::
ProjectMonthlyUsage
.
find_or_create_current
(
project_id:
project
.
id
).
amount_used
}
let
(
:service
)
{
described_class
.
new
(
project
.
id
,
namespace
.
id
,
build
.
id
)
}
let
(
:service
)
{
described_class
.
new
(
project
.
id
,
namespace
.
id
,
build
.
id
)
}
describe
'#execute'
,
:clean_gitlab_redis_shared_state
do
describe
'#execute'
,
:clean_gitlab_redis_shared_state
do
subject
{
service
.
execute
(
consumption_minutes
)
}
subject
{
service
.
execute
(
consumption_minutes
,
duration
)
}
shared_examples
'updates legacy consumption'
do
shared_examples
'updates legacy consumption'
do
it
'updates legacy statistics with consumption seconds'
do
it
'updates legacy statistics with consumption seconds'
do
...
@@ -26,10 +27,20 @@ RSpec.describe Ci::Minutes::UpdateProjectAndNamespaceUsageService do
...
@@ -26,10 +27,20 @@ RSpec.describe Ci::Minutes::UpdateProjectAndNamespaceUsageService do
end
end
shared_examples
'updates monthly consumption'
do
shared_examples
'updates monthly consumption'
do
it
'updates monthly usage with consumption minutes'
do
it
'updates monthly usage for namespace'
do
current_usage
=
Ci
::
Minutes
::
NamespaceMonthlyUsage
.
find_or_create_current
(
namespace_id:
namespace
.
id
)
expect
{
subject
}
.
to
change
{
current_usage
.
reload
.
amount_used
}.
by
(
consumption_minutes
)
.
and
change
{
current_usage
.
reload
.
shared_runners_duration
}.
by
(
duration
)
end
it
'updates monthly usage for project'
do
current_usage
=
Ci
::
Minutes
::
ProjectMonthlyUsage
.
find_or_create_current
(
project_id:
project
.
id
)
expect
{
subject
}
expect
{
subject
}
.
to
change
{
Ci
::
Minutes
::
NamespaceMonthlyUsage
.
find_or_create_current
(
namespace_id:
namespace
.
id
)
.
amount_used
}.
by
(
consumption_minutes
)
.
to
change
{
current_usage
.
reload
.
amount_used
}.
by
(
consumption_minutes
)
.
and
change
{
Ci
::
Minutes
::
ProjectMonthlyUsage
.
find_or_create_current
(
project_id:
project
.
id
).
amount_used
}.
by
(
consumption_minutes
)
.
and
change
{
current_usage
.
reload
.
shared_runners_duration
}.
by
(
duration
)
end
end
end
end
...
...
ee/spec/services/ci/sync_reports_to_approval_rules_service_spec.rb
View file @
0854b021
...
@@ -22,9 +22,10 @@ RSpec.describe Ci::SyncReportsToApprovalRulesService, '#execute' do
...
@@ -22,9 +22,10 @@ RSpec.describe Ci::SyncReportsToApprovalRulesService, '#execute' do
let
(
:scanners
)
{
%w[dependency_scanning]
}
let
(
:scanners
)
{
%w[dependency_scanning]
}
let
(
:vulnerabilities_allowed
)
{
0
}
let
(
:vulnerabilities_allowed
)
{
0
}
let
(
:severity_levels
)
{
%w[high unknown]
}
let
(
:severity_levels
)
{
%w[high unknown]
}
let
(
:vulnerability_states
)
{
%w(newly_detected)
}
before
do
before
do
create
(
:approval_project_rule
,
:vulnerability
,
project:
project
,
approvals_required:
2
,
scanners:
scanners
,
vulnerabilities_allowed:
vulnerabilities_allowed
,
severity_levels:
severity_levels
)
create
(
:approval_project_rule
,
:vulnerability
,
project:
project
,
approvals_required:
2
,
scanners:
scanners
,
vulnerabilities_allowed:
vulnerabilities_allowed
,
severity_levels:
severity_levels
,
vulnerability_states:
vulnerability_states
)
end
end
context
'when there are security reports'
do
context
'when there are security reports'
do
...
@@ -78,6 +79,15 @@ RSpec.describe Ci::SyncReportsToApprovalRulesService, '#execute' do
...
@@ -78,6 +79,15 @@ RSpec.describe Ci::SyncReportsToApprovalRulesService, '#execute' do
.
to
change
{
report_approver_rule
.
reload
.
approvals_required
}.
from
(
2
).
to
(
0
)
.
to
change
{
report_approver_rule
.
reload
.
approvals_required
}.
from
(
2
).
to
(
0
)
end
end
end
end
context
'without any vulnerability state related to the security reports'
do
let
(
:vulnerability_states
)
{
%w(resolved)
}
it
'lowers approvals_required count to zero'
do
expect
{
subject
}
.
to
change
{
report_approver_rule
.
reload
.
approvals_required
}.
from
(
2
).
to
(
0
)
end
end
end
end
context
'when only low-severity vulnerabilities are present'
do
context
'when only low-severity vulnerabilities are present'
do
...
...
ee/spec/support/shared_examples/models/ci/increase_usage_shared_examples.rb
0 → 100644
View file @
0854b021
# frozen_string_literal: true
RSpec
.
shared_examples_for
'CI minutes increase usage'
do
subject
{
described_class
.
increase_usage
(
current_usage
,
increments
)
}
let
(
:increments
)
{
{
amount_used:
amount
}
}
context
'when amount is greater than 0'
do
let
(
:amount
)
{
10.5
}
it
'updates the current month usage'
do
subject
expect
(
current_usage
.
reload
.
amount_used
).
to
eq
(
110.5
)
end
end
context
'when amount is less or equal to 0'
do
let
(
:amount
)
{
-
2.0
}
it
'does not update the current month usage'
do
subject
expect
(
current_usage
.
reload
.
amount_used
).
to
eq
(
100.0
)
end
end
context
'when shared_runners_duration is incremented'
do
let
(
:increments
)
{
{
amount_used:
amount
,
shared_runners_duration:
duration
}
}
let
(
:amount
)
{
10.5
}
context
'when duration is positive'
do
let
(
:duration
)
{
10
}
it
'updates the duration and amount used'
do
subject
expect
(
current_usage
.
reload
.
amount_used
).
to
eq
(
110.5
)
expect
(
current_usage
.
shared_runners_duration
).
to
eq
(
10
)
end
context
'when amount_used is zero'
do
let
(
:amount
)
{
0
}
it
'updates only the duration'
do
subject
expect
(
current_usage
.
reload
.
amount_used
).
to
eq
(
100.0
)
expect
(
current_usage
.
shared_runners_duration
).
to
eq
(
10
)
end
end
end
context
'when duration is zero'
do
let
(
:duration
)
{
0
}
it
'updates only the amount used'
do
subject
expect
(
current_usage
.
reload
.
amount_used
).
to
eq
(
110.5
)
expect
(
current_usage
.
shared_runners_duration
).
to
eq
(
0
)
end
context
'when amount_used is zero'
do
let
(
:amount
)
{
0
}
it
'does not perform updates'
do
subject
expect
(
current_usage
.
reload
.
amount_used
).
to
eq
(
100.0
)
expect
(
current_usage
.
shared_runners_duration
).
to
eq
(
0
)
end
end
end
end
end
ee/spec/workers/ci/minutes/update_project_and_namespace_usage_worker_spec.rb
View file @
0854b021
...
@@ -9,35 +9,78 @@ RSpec.describe Ci::Minutes::UpdateProjectAndNamespaceUsageWorker do
...
@@ -9,35 +9,78 @@ RSpec.describe Ci::Minutes::UpdateProjectAndNamespaceUsageWorker do
let
(
:consumption
)
{
100
}
let
(
:consumption
)
{
100
}
let
(
:consumption_seconds
)
{
consumption
*
60
}
let
(
:consumption_seconds
)
{
consumption
*
60
}
let
(
:duration
)
{
60_000
}
let
(
:worker
)
{
described_class
.
new
}
let
(
:worker
)
{
described_class
.
new
}
describe
'#perform'
,
:clean_gitlab_redis_shared_state
do
describe
'#perform'
,
:clean_gitlab_redis_shared_state
do
subject
{
perform_multiple
([
consumption
,
project
.
id
,
namespace
.
id
,
build
.
id
])
}
context
'when duration param is not passed in'
do
subject
{
perform_multiple
([
consumption
,
project
.
id
,
namespace
.
id
,
build
.
id
])
}
context
'behaves idempotently for monthly usage update'
do
context
'behaves idempotently for monthly usage update'
do
it
'executes UpdateProjectAndNamespaceUsageService'
do
it
'executes UpdateProjectAndNamespaceUsageService'
do
service_instance
=
double
service_instance
=
double
expect
(
::
Ci
::
Minutes
::
UpdateProjectAndNamespaceUsageService
).
to
receive
(
:new
).
at_least
(
:once
).
and_return
(
service_instance
)
expect
(
::
Ci
::
Minutes
::
UpdateProjectAndNamespaceUsageService
).
to
receive
(
:new
).
at_least
(
:once
).
and_return
(
service_instance
)
expect
(
service_instance
).
to
receive
(
:execute
).
at_least
(
:once
).
with
(
consumption
)
expect
(
service_instance
).
to
receive
(
:execute
).
at_least
(
:once
).
with
(
consumption
,
0
)
subject
subject
end
it
'updates monthly usage but not shared_runners_duration'
do
subject
namespace_usage
=
Ci
::
Minutes
::
NamespaceMonthlyUsage
.
find_by
(
namespace:
namespace
)
expect
(
namespace_usage
.
amount_used
).
to
eq
(
consumption
)
expect
(
namespace_usage
.
shared_runners_duration
).
to
eq
(
0
)
project_usage
=
Ci
::
Minutes
::
ProjectMonthlyUsage
.
find_by
(
project:
project
)
expect
(
project_usage
.
amount_used
).
to
eq
(
consumption
)
expect
(
project_usage
.
shared_runners_duration
).
to
eq
(
0
)
end
end
end
it
'updates monthly usage'
do
it
'does not behave idempotently for legacy statistics update'
do
expect
(
::
Ci
::
Minutes
::
UpdateProjectAndNamespaceUsageService
).
to
receive
(
:new
).
twice
.
and_call_original
subject
subject
expect
(
Ci
::
Minutes
::
NamespaceMonthlyUsage
.
find_by
(
namespace:
namespace
).
amount_used
).
to
eq
(
consumption
)
expect
(
project
.
statistics
.
reload
.
shared_runners_seconds
).
to
eq
(
2
*
consumption_seconds
)
expect
(
Ci
::
Minutes
::
ProjectMonthlyUsage
.
find_by
(
project:
project
).
amount_used
).
to
eq
(
consumption
)
expect
(
namespace
.
reload
.
namespace_statistics
.
shared_runners_seconds
).
to
eq
(
2
*
consumption_seconds
)
end
end
end
end
it
'does not behave idempotently for legacy statistics update'
do
context
'when duration param is passed in'
do
expect
(
::
Ci
::
Minutes
::
UpdateProjectAndNamespaceUsageService
).
to
receive
(
:new
).
twice
.
and_call_original
subject
{
perform_multiple
([
consumption
,
project
.
id
,
namespace
.
id
,
build
.
id
,
{
duration:
duration
}])
}
context
'behaves idempotently for monthly usage update'
do
it
'executes UpdateProjectAndNamespaceUsageService'
do
service_instance
=
double
expect
(
::
Ci
::
Minutes
::
UpdateProjectAndNamespaceUsageService
).
to
receive
(
:new
).
at_least
(
:once
).
and_return
(
service_instance
)
expect
(
service_instance
).
to
receive
(
:execute
).
at_least
(
:once
).
with
(
consumption
,
duration
)
subject
end
subject
it
'updates monthly usage and shared_runners_duration'
do
subject
expect
(
project
.
statistics
.
reload
.
shared_runners_seconds
).
to
eq
(
2
*
consumption_seconds
)
namespace_usage
=
Ci
::
Minutes
::
NamespaceMonthlyUsage
.
find_by
(
namespace:
namespace
)
expect
(
namespace
.
reload
.
namespace_statistics
.
shared_runners_seconds
).
to
eq
(
2
*
consumption_seconds
)
expect
(
namespace_usage
.
amount_used
).
to
eq
(
consumption
)
expect
(
namespace_usage
.
shared_runners_duration
).
to
eq
(
duration
)
project_usage
=
Ci
::
Minutes
::
ProjectMonthlyUsage
.
find_by
(
project:
project
)
expect
(
project_usage
.
amount_used
).
to
eq
(
consumption
)
expect
(
project_usage
.
shared_runners_duration
).
to
eq
(
duration
)
end
end
it
'does not behave idempotently for legacy statistics update'
do
expect
(
::
Ci
::
Minutes
::
UpdateProjectAndNamespaceUsageService
).
to
receive
(
:new
).
twice
.
and_call_original
subject
expect
(
project
.
statistics
.
reload
.
shared_runners_seconds
).
to
eq
(
2
*
consumption_seconds
)
expect
(
namespace
.
reload
.
namespace_statistics
.
shared_runners_seconds
).
to
eq
(
2
*
consumption_seconds
)
end
end
end
end
end
end
end
lib/gitlab/ci/reports/security/reports.rb
View file @
0854b021
...
@@ -22,21 +22,24 @@ module Gitlab
...
@@ -22,21 +22,24 @@ module Gitlab
reports
.
values
.
flat_map
(
&
:findings
)
reports
.
values
.
flat_map
(
&
:findings
)
end
end
def
violates_default_policy_against?
(
target_reports
,
vulnerabilities_allowed
,
severity_levels
)
def
violates_default_policy_against?
(
target_reports
,
vulnerabilities_allowed
,
severity_levels
,
vulnerability_states
)
unsafe_findings_count
(
target_reports
,
severity_levels
)
>
vulnerabilities_allowed
unsafe_findings_count
(
target_reports
,
severity_levels
,
vulnerability_states
)
>
vulnerabilities_allowed
end
end
private
def
unsafe_findings_uuids
(
severity_levels
)
findings
.
select
{
|
finding
|
finding
.
unsafe?
(
severity_levels
)
}.
map
(
&
:uuid
)
def
findings_diff
(
target_reports
)
findings
-
target_reports
&
.
findings
.
to_a
end
end
def
unsafe_findings_count
(
target_reports
,
severity_levels
)
private
findings_diff
(
target_reports
).
count
{
|
finding
|
finding
.
unsafe?
(
severity_levels
)}
def
unsafe_findings_count
(
target_reports
,
severity_levels
,
vulnerability_states
)
new_uuids
=
unsafe_findings_uuids
(
severity_levels
)
-
target_reports
&
.
unsafe_findings_uuids
(
severity_levels
).
to_a
new_uuids
.
count
end
end
end
end
end
end
end
end
end
end
end
end
Gitlab
::
Ci
::
Reports
::
Security
::
Reports
.
prepend_mod_with
(
'Gitlab::Ci::Reports::Security::Reports'
)
lib/gitlab/usage/metrics/names_suggestions/generator.rb
View file @
0854b021
...
@@ -10,10 +10,10 @@ module Gitlab
...
@@ -10,10 +10,10 @@ module Gitlab
uncached_data
.
deep_stringify_keys
.
dig
(
*
key_path
.
split
(
'.'
))
uncached_data
.
deep_stringify_keys
.
dig
(
*
key_path
.
split
(
'.'
))
end
end
def
add_metric
(
metric
,
time_frame:
'none'
)
def
add_metric
(
metric
,
time_frame:
'none'
,
options:
{}
)
metric_class
=
"Gitlab::Usage::Metrics::Instrumentations::
#{
metric
}
"
.
constantize
metric_class
=
"Gitlab::Usage::Metrics::Instrumentations::
#{
metric
}
"
.
constantize
metric_class
.
new
(
time_frame:
time_frame
).
suggested_name
metric_class
.
new
(
time_frame:
time_frame
,
options:
options
).
suggested_name
end
end
private
private
...
...
lib/gitlab/usage_data_non_sql_metrics.rb
View file @
0854b021
...
@@ -12,10 +12,10 @@ module Gitlab
...
@@ -12,10 +12,10 @@ module Gitlab
super
.
with_indifferent_access
.
deep_merge
(
instrumentation_metrics
.
with_indifferent_access
)
super
.
with_indifferent_access
.
deep_merge
(
instrumentation_metrics
.
with_indifferent_access
)
end
end
def
add_metric
(
metric
,
time_frame:
'none'
)
def
add_metric
(
metric
,
time_frame:
'none'
,
options:
{}
)
metric_class
=
"Gitlab::Usage::Metrics::Instrumentations::
#{
metric
}
"
.
constantize
metric_class
=
"Gitlab::Usage::Metrics::Instrumentations::
#{
metric
}
"
.
constantize
metric_class
.
new
(
time_frame:
time_frame
).
instrumentation
metric_class
.
new
(
time_frame:
time_frame
,
options:
options
).
instrumentation
end
end
def
count
(
relation
,
column
=
nil
,
batch:
true
,
batch_size:
nil
,
start:
nil
,
finish:
nil
)
def
count
(
relation
,
column
=
nil
,
batch:
true
,
batch_size:
nil
,
start:
nil
,
finish:
nil
)
...
...
lib/gitlab/usage_data_queries.rb
View file @
0854b021
...
@@ -12,10 +12,10 @@ module Gitlab
...
@@ -12,10 +12,10 @@ module Gitlab
super
.
with_indifferent_access
.
deep_merge
(
instrumentation_metrics
.
with_indifferent_access
)
super
.
with_indifferent_access
.
deep_merge
(
instrumentation_metrics
.
with_indifferent_access
)
end
end
def
add_metric
(
metric
,
time_frame:
'none'
)
def
add_metric
(
metric
,
time_frame:
'none'
,
options:
{}
)
metric_class
=
"Gitlab::Usage::Metrics::Instrumentations::
#{
metric
}
"
.
constantize
metric_class
=
"Gitlab::Usage::Metrics::Instrumentations::
#{
metric
}
"
.
constantize
metric_class
.
new
(
time_frame:
time_frame
).
instrumentation
metric_class
.
new
(
time_frame:
time_frame
,
options:
options
).
instrumentation
end
end
def
count
(
relation
,
column
=
nil
,
*
args
,
**
kwargs
)
def
count
(
relation
,
column
=
nil
,
*
args
,
**
kwargs
)
...
...
lib/gitlab/utils/usage_data.rb
View file @
0854b021
...
@@ -45,14 +45,14 @@ module Gitlab
...
@@ -45,14 +45,14 @@ module Gitlab
MAX_BUCKET_SIZE
=
100
MAX_BUCKET_SIZE
=
100
INSTRUMENTATION_CLASS_FALLBACK
=
-
100
INSTRUMENTATION_CLASS_FALLBACK
=
-
100
def
add_metric
(
metric
,
time_frame:
'none'
)
def
add_metric
(
metric
,
time_frame:
'none'
,
options:
{}
)
# Results of this method should be overwritten by instrumentation class values
# Results of this method should be overwritten by instrumentation class values
# -100 indicates the metric was not properly merged.
# -100 indicates the metric was not properly merged.
return
INSTRUMENTATION_CLASS_FALLBACK
if
Feature
.
enabled?
(
:usage_data_instrumentation
)
return
INSTRUMENTATION_CLASS_FALLBACK
if
Feature
.
enabled?
(
:usage_data_instrumentation
)
metric_class
=
"Gitlab::Usage::Metrics::Instrumentations::
#{
metric
}
"
.
constantize
metric_class
=
"Gitlab::Usage::Metrics::Instrumentations::
#{
metric
}
"
.
constantize
metric_class
.
new
(
time_frame:
time_frame
).
value
metric_class
.
new
(
time_frame:
time_frame
,
options:
options
).
value
end
end
def
count
(
relation
,
column
=
nil
,
batch:
true
,
batch_size:
nil
,
start:
nil
,
finish:
nil
)
def
count
(
relation
,
column
=
nil
,
batch:
true
,
batch_size:
nil
,
start:
nil
,
finish:
nil
)
...
...
locale/gitlab.pot
View file @
0854b021
...
@@ -4223,12 +4223,18 @@ msgstr ""
...
@@ -4223,12 +4223,18 @@ msgstr ""
msgid "ApprovalRule|All severity levels"
msgid "ApprovalRule|All severity levels"
msgstr ""
msgstr ""
msgid "ApprovalRule|All vulnerability states"
msgstr ""
msgid "ApprovalRule|Apply this approval rule to consider only the selected security scanners."
msgid "ApprovalRule|Apply this approval rule to consider only the selected security scanners."
msgstr ""
msgstr ""
msgid "ApprovalRule|Apply this approval rule to consider only the selected severity levels."
msgid "ApprovalRule|Apply this approval rule to consider only the selected severity levels."
msgstr ""
msgstr ""
msgid "ApprovalRule|Apply this approval rule to consider only the selected vulnerability states."
msgstr ""
msgid "ApprovalRule|Approval rules"
msgid "ApprovalRule|Approval rules"
msgstr ""
msgstr ""
...
@@ -4241,12 +4247,21 @@ msgstr ""
...
@@ -4241,12 +4247,21 @@ msgstr ""
msgid "ApprovalRule|Approvers"
msgid "ApprovalRule|Approvers"
msgstr ""
msgstr ""
msgid "ApprovalRule|Confirmed"
msgstr ""
msgid "ApprovalRule|Dismissed"
msgstr ""
msgid "ApprovalRule|Examples: QA, Security."
msgid "ApprovalRule|Examples: QA, Security."
msgstr ""
msgstr ""
msgid "ApprovalRule|Name"
msgid "ApprovalRule|Name"
msgstr ""
msgstr ""
msgid "ApprovalRule|Newly detected"
msgstr ""
msgid "ApprovalRule|Number of vulnerabilities allowed before approval rule is triggered."
msgid "ApprovalRule|Number of vulnerabilities allowed before approval rule is triggered."
msgstr ""
msgstr ""
...
@@ -4259,6 +4274,15 @@ msgstr ""
...
@@ -4259,6 +4274,15 @@ msgstr ""
msgid "ApprovalRule|Please select at least one severity level"
msgid "ApprovalRule|Please select at least one severity level"
msgstr ""
msgstr ""
msgid "ApprovalRule|Please select at least one vulnerability state"
msgstr ""
msgid "ApprovalRule|Previously detected"
msgstr ""
msgid "ApprovalRule|Resolved"
msgstr ""
msgid "ApprovalRule|Rule name"
msgid "ApprovalRule|Rule name"
msgstr ""
msgstr ""
...
@@ -4274,6 +4298,9 @@ msgstr ""
...
@@ -4274,6 +4298,9 @@ msgstr ""
msgid "ApprovalRule|Select severity levels"
msgid "ApprovalRule|Select severity levels"
msgstr ""
msgstr ""
msgid "ApprovalRule|Select vulnerability states"
msgstr ""
msgid "ApprovalRule|Severity levels"
msgid "ApprovalRule|Severity levels"
msgstr ""
msgstr ""
...
@@ -4283,6 +4310,9 @@ msgstr ""
...
@@ -4283,6 +4310,9 @@ msgstr ""
msgid "ApprovalRule|Vulnerabilities allowed"
msgid "ApprovalRule|Vulnerabilities allowed"
msgstr ""
msgstr ""
msgid "ApprovalRule|Vulnerability states"
msgstr ""
msgid "ApprovalSettings|Merge request approval settings have been updated."
msgid "ApprovalSettings|Merge request approval settings have been updated."
msgstr ""
msgstr ""
...
...
spec/frontend/lib/utils/common_utils_spec.js
View file @
0854b021
...
@@ -1008,6 +1008,21 @@ describe('common_utils', () => {
...
@@ -1008,6 +1008,21 @@ describe('common_utils', () => {
});
});
});
});
describe
(
'
scopedLabelKey
'
,
()
=>
{
it
.
each
`
label | expectedLabelKey
${
undefined
}
|
${
''
}
${
''
}
|
${
''
}
${
'
title
'
}
|
${
'
title
'
}
${
'
scoped::value
'
}
|
${
'
scoped
'
}
${
'
scoped::label::value
'
}
|
${
'
scoped::label
'
}
${
'
scoped::label-some::value
'
}
|
${
'
scoped::label-some
'
}
${
'
scoped::label::some::value
'
}
|
${
'
scoped::label::some
'
}
`
(
'
returns "$expectedLabelKey" when label is "$label"
'
,
({
label
,
expectedLabelKey
})
=>
{
expect
(
commonUtils
.
scopedLabelKey
({
title
:
label
})).
toBe
(
expectedLabelKey
);
});
});
describe
(
'
getDashPath
'
,
()
=>
{
describe
(
'
getDashPath
'
,
()
=>
{
it
(
'
returns the path following /-/
'
,
()
=>
{
it
(
'
returns the path following /-/
'
,
()
=>
{
expect
(
commonUtils
.
getDashPath
(
'
/some/-/url-with-dashes-/
'
)).
toEqual
(
'
url-with-dashes-/
'
);
expect
(
commonUtils
.
getDashPath
(
'
/some/-/url-with-dashes-/
'
)).
toEqual
(
'
url-with-dashes-/
'
);
...
...
spec/frontend/vue_shared/components/sidebar/labels_select_vue/store/mutations_spec.js
View file @
0854b021
import
{
cloneDeep
}
from
'
lodash
'
;
import
*
as
types
from
'
~/vue_shared/components/sidebar/labels_select_vue/store/mutation_types
'
;
import
*
as
types
from
'
~/vue_shared/components/sidebar/labels_select_vue/store/mutation_types
'
;
import
mutations
from
'
~/vue_shared/components/sidebar/labels_select_vue/store/mutations
'
;
import
mutations
from
'
~/vue_shared/components/sidebar/labels_select_vue/store/mutations
'
;
...
@@ -153,47 +154,40 @@ describe('LabelsSelect Mutations', () => {
...
@@ -153,47 +154,40 @@ describe('LabelsSelect Mutations', () => {
});
});
describe
(
`
${
types
.
UPDATE_SELECTED_LABELS
}
`
,
()
=>
{
describe
(
`
${
types
.
UPDATE_SELECTED_LABELS
}
`
,
()
=>
{
let
labels
;
const
labels
=
[
{
id
:
1
,
title
:
'
scoped
'
},
beforeEach
(()
=>
{
{
id
:
2
,
title
:
'
scoped::label::one
'
,
set
:
false
},
labels
=
[
{
id
:
3
,
title
:
'
scoped::label::two
'
,
set
:
false
},
{
id
:
1
,
title
:
'
scoped
'
},
{
id
:
4
,
title
:
'
scoped::label::three
'
,
set
:
true
},
{
id
:
2
,
title
:
'
scoped::one
'
,
set
:
false
},
{
id
:
5
,
title
:
'
scoped::one
'
,
set
:
false
},
{
id
:
3
,
title
:
'
scoped::test
'
,
set
:
true
},
{
id
:
6
,
title
:
'
scoped::two
'
,
set
:
false
},
{
id
:
4
,
title
:
''
},
{
id
:
7
,
title
:
'
scoped::three
'
,
set
:
true
},
];
{
id
:
8
,
title
:
''
},
});
];
it
(
'
updates `state.labels` to include `touched` and `set` props based on provided `labels` param
'
,
()
=>
{
it
.
each
`
const
updatedLabelIds
=
[
2
];
label | labelGroupIds
const
state
=
{
${
labels
[
0
]}
|
${[]}
labels
,
${
labels
[
1
]}
|
${[
labels
[
2
],
labels
[
3
]]}
};
${
labels
[
2
]}
|
${[
labels
[
1
],
labels
[
3
]]}
mutations
[
types
.
UPDATE_SELECTED_LABELS
](
state
,
{
labels
:
[{
id
:
2
}]
});
${
labels
[
3
]}
|
${[
labels
[
1
],
labels
[
2
]]}
${
labels
[
4
]}
|
${[
labels
[
5
],
labels
[
6
]]}
state
.
labels
.
forEach
((
label
)
=>
{
${
labels
[
5
]}
|
${[
labels
[
4
],
labels
[
6
]]}
if
(
updatedLabelIds
.
includes
(
label
.
id
))
{
${
labels
[
6
]}
|
${[
labels
[
4
],
labels
[
5
]]}
expect
(
label
.
touched
).
toBe
(
true
);
${
labels
[
7
]}
|
${[]}
expect
(
label
.
set
).
toBe
(
true
);
`
(
'
updates `touched` and `set` props for $label.title
'
,
({
label
,
labelGroupIds
})
=>
{
}
const
state
=
{
labels
:
cloneDeep
(
labels
)
};
mutations
[
types
.
UPDATE_SELECTED_LABELS
](
state
,
{
labels
:
[{
id
:
label
.
id
}]
});
expect
(
state
.
labels
[
label
.
id
-
1
]).
toMatchObject
({
touched
:
true
,
set
:
!
labels
[
label
.
id
-
1
].
set
,
});
});
});
describe
(
'
when label is scoped
'
,
()
=>
{
labelGroupIds
.
forEach
((
l
)
=>
{
it
(
'
unsets the currently selected scoped label and sets the current label
'
,
()
=>
{
expect
(
state
.
labels
[
l
.
id
-
1
].
touched
).
toBeFalsy
();
const
state
=
{
expect
(
state
.
labels
[
l
.
id
-
1
].
set
).
toBe
(
false
);
labels
,
};
mutations
[
types
.
UPDATE_SELECTED_LABELS
](
state
,
{
labels
:
[{
id
:
2
,
title
:
'
scoped::one
'
}],
});
expect
(
state
.
labels
).
toEqual
([
{
id
:
1
,
title
:
'
scoped
'
},
{
id
:
2
,
title
:
'
scoped::one
'
,
set
:
true
,
touched
:
true
},
{
id
:
3
,
title
:
'
scoped::test
'
,
set
:
false
},
{
id
:
4
,
title
:
''
},
]);
});
});
});
});
});
});
...
...
spec/lib/gitlab/ci/reports/security/reports_spec.rb
View file @
0854b021
...
@@ -57,8 +57,9 @@ RSpec.describe Gitlab::Ci::Reports::Security::Reports do
...
@@ -57,8 +57,9 @@ RSpec.describe Gitlab::Ci::Reports::Security::Reports do
let
(
:high_severity_dast
)
{
build
(
:ci_reports_security_finding
,
severity:
'high'
,
report_type: :dast
)
}
let
(
:high_severity_dast
)
{
build
(
:ci_reports_security_finding
,
severity:
'high'
,
report_type: :dast
)
}
let
(
:vulnerabilities_allowed
)
{
0
}
let
(
:vulnerabilities_allowed
)
{
0
}
let
(
:severity_levels
)
{
%w(critical high)
}
let
(
:severity_levels
)
{
%w(critical high)
}
let
(
:vulnerability_states
)
{
%w(newly_detected)
}
subject
{
security_reports
.
violates_default_policy_against?
(
target_reports
,
vulnerabilities_allowed
,
severity_levels
)
}
subject
{
security_reports
.
violates_default_policy_against?
(
target_reports
,
vulnerabilities_allowed
,
severity_levels
,
vulnerability_states
)
}
before
do
before
do
security_reports
.
get_report
(
'sast'
,
artifact
).
add_finding
(
high_severity_dast
)
security_reports
.
get_report
(
'sast'
,
artifact
).
add_finding
(
high_severity_dast
)
...
...
spec/workers/concerns/application_worker_spec.rb
View file @
0854b021
...
@@ -341,6 +341,7 @@ RSpec.describe ApplicationWorker do
...
@@ -341,6 +341,7 @@ RSpec.describe ApplicationWorker do
it
'enqueues jobs in one go'
do
it
'enqueues jobs in one go'
do
expect
(
Sidekiq
::
Client
).
to
(
expect
(
Sidekiq
::
Client
).
to
(
receive
(
:push_bulk
).
with
(
hash_including
(
'args'
=>
args
)).
once
.
and_call_original
)
receive
(
:push_bulk
).
with
(
hash_including
(
'args'
=>
args
)).
once
.
and_call_original
)
expect
(
Sidekiq
.
logger
).
not_to
receive
(
:info
)
perform_action
perform_action
...
@@ -349,6 +350,19 @@ RSpec.describe ApplicationWorker do
...
@@ -349,6 +350,19 @@ RSpec.describe ApplicationWorker do
end
end
end
end
shared_examples_for
'logs bulk insertions'
do
it
'logs arguments and job IDs'
do
worker
.
log_bulk_perform_async!
expect
(
Sidekiq
.
logger
).
to
(
receive
(
:info
).
with
(
hash_including
(
'args_list'
=>
args
)).
once
.
and_call_original
)
expect
(
Sidekiq
.
logger
).
to
(
receive
(
:info
).
with
(
hash_including
(
'jid_list'
=>
anything
)).
once
.
and_call_original
)
perform_action
end
end
before
do
before
do
stub_const
(
worker
.
name
,
worker
)
stub_const
(
worker
.
name
,
worker
)
end
end
...
@@ -381,6 +395,7 @@ RSpec.describe ApplicationWorker do
...
@@ -381,6 +395,7 @@ RSpec.describe ApplicationWorker do
include_context
'set safe limit beyond the number of jobs to be enqueued'
include_context
'set safe limit beyond the number of jobs to be enqueued'
it_behaves_like
'enqueues jobs in one go'
it_behaves_like
'enqueues jobs in one go'
it_behaves_like
'logs bulk insertions'
it_behaves_like
'returns job_id of all enqueued jobs'
it_behaves_like
'returns job_id of all enqueued jobs'
it_behaves_like
'does not schedule the jobs for any specific time'
it_behaves_like
'does not schedule the jobs for any specific time'
end
end
...
@@ -400,6 +415,7 @@ RSpec.describe ApplicationWorker do
...
@@ -400,6 +415,7 @@ RSpec.describe ApplicationWorker do
include_context
'set safe limit beyond the number of jobs to be enqueued'
include_context
'set safe limit beyond the number of jobs to be enqueued'
it_behaves_like
'enqueues jobs in one go'
it_behaves_like
'enqueues jobs in one go'
it_behaves_like
'logs bulk insertions'
it_behaves_like
'returns job_id of all enqueued jobs'
it_behaves_like
'returns job_id of all enqueued jobs'
it_behaves_like
'does not schedule the jobs for any specific time'
it_behaves_like
'does not schedule the jobs for any specific time'
end
end
...
...
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