diff options
180 files changed, 3005 insertions, 6359 deletions
diff --git a/.gitlab/ci/reports.gitlab-ci.yml b/.gitlab/ci/reports.gitlab-ci.yml index ca55bbd32a7..fc0e93ee9f1 100644 --- a/.gitlab/ci/reports.gitlab-ci.yml +++ b/.gitlab/ci/reports.gitlab-ci.yml @@ -2,6 +2,7 @@ include: - template: Code-Quality.gitlab-ci.yml - template: Security/SAST.gitlab-ci.yml - template: Security/Dependency-Scanning.gitlab-ci.yml + - template: Security/DAST.gitlab-ci.yml code_quality: extends: .dedicated-no-docs @@ -24,3 +25,12 @@ dependency_scanning: tags: [] before_script: [] cache: {} + +dast: + extends: .dedicated-no-docs + stage: qa + dependencies: + - review-deploy + before_script: + - export DAST_WEBSITE="$(cat review_app_url.txt)" + cache: {} diff --git a/GITLAB_SHELL_VERSION b/GITLAB_SHELL_VERSION index b13d146a7b0..ccfb75e5120 100644 --- a/GITLAB_SHELL_VERSION +++ b/GITLAB_SHELL_VERSION @@ -1 +1 @@ -9.3.0 +9.4.1 @@ -275,7 +275,6 @@ gem 'font-awesome-rails', '~> 4.7' gem 'gemojione', '~> 3.3' gem 'gon', '~> 6.2' gem 'request_store', '~> 1.3' -gem 'virtus', '~> 1.0.1' gem 'base32', '~> 0.3.0' # Sentry integration diff --git a/Gemfile.lock b/Gemfile.lock index d8f7ca994da..0ecf3aa2840 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1252,7 +1252,6 @@ DEPENDENCIES unicorn-worker-killer (~> 0.4.4) validates_hostname (~> 1.0.6) version_sorter (~> 2.2.4) - virtus (~> 1.0.1) vmstat (~> 2.3.0) webmock (~> 3.5.1) webpack-rails (~> 0.9.10) diff --git a/app/assets/javascripts/diffs/components/diff_expansion_cell.vue b/app/assets/javascripts/diffs/components/diff_expansion_cell.vue index 925385fa98a..839ab542377 100644 --- a/app/assets/javascripts/diffs/components/diff_expansion_cell.vue +++ b/app/assets/javascripts/diffs/components/diff_expansion_cell.vue @@ -212,19 +212,18 @@ export default { </script> <template> - <td :colspan="colspan"> + <td :colspan="colspan" class="text-center"> <div class="content js-line-expansion-content"> <a v-if="canExpandUp" v-tooltip - class="cursor-pointer js-unfold unfold-icon" + class="cursor-pointer js-unfold unfold-icon d-inline-block pt-2 pb-2" data-placement="top" data-container="body" :title="__('Expand up')" @click="handleExpandLines(EXPAND_UP)" > - <!-- TODO: remove style & replace with correct icon, waiting for MR https://gitlab.com/gitlab-org/gitlab-design/issues/499 --> - <icon :size="12" name="expand-left" aria-hidden="true" style="transform: rotate(270deg);" /> + <icon :size="12" name="expand-up" aria-hidden="true" /> </a> <a class="mx-2 cursor-pointer js-unfold-all" @click="handleExpandLines()"> <span>{{ s__('Diffs|Show all lines') }}</span> @@ -232,14 +231,13 @@ export default { <a v-if="canExpandDown" v-tooltip - class="cursor-pointer js-unfold-down has-tooltip unfold-icon" + class="cursor-pointer js-unfold-down has-tooltip unfold-icon d-inline-block pt-2 pb-2" data-placement="top" data-container="body" :title="__('Expand down')" @click="handleExpandLines(EXPAND_DOWN)" > - <!-- TODO: remove style & replace with correct icon, waiting for MR https://gitlab.com/gitlab-org/gitlab-design/issues/499 --> - <icon :size="12" name="expand-left" aria-hidden="true" style="transform: rotate(90deg);" /> + <icon :size="12" name="expand-down" aria-hidden="true" /> </a> </div> </td> diff --git a/app/assets/javascripts/lib/utils/url_utility.js b/app/assets/javascripts/lib/utils/url_utility.js index 1336b6a5461..7ead9d46fbb 100644 --- a/app/assets/javascripts/lib/utils/url_utility.js +++ b/app/assets/javascripts/lib/utils/url_utility.js @@ -1,5 +1,11 @@ import { join as joinPaths } from 'path'; +// Returns a decoded url parameter value +// - Treats '+' as '%20' +function decodeUrlParameter(val) { + return decodeURIComponent(val.replace(/\+/g, '%20')); +} + // Returns an array containing the value(s) of the // of the key passed as an argument export function getParameterValues(sParam, url = window.location) { @@ -30,7 +36,7 @@ export function mergeUrlParams(params, url) { .forEach(part => { if (part.length) { const kv = part.split('='); - merged[decodeURIComponent(kv[0])] = decodeURIComponent(kv.slice(1).join('=')); + merged[decodeUrlParameter(kv[0])] = decodeUrlParameter(kv.slice(1).join('=')); } }); } diff --git a/app/assets/javascripts/monitoring/components/dashboard.vue b/app/assets/javascripts/monitoring/components/dashboard.vue index dfeeba238ca..c414c26ca61 100644 --- a/app/assets/javascripts/monitoring/components/dashboard.vue +++ b/app/assets/javascripts/monitoring/components/dashboard.vue @@ -264,12 +264,12 @@ export default { showToast() { this.$toast.show(__('Link copied to clipboard')); }, + // TODO: END generateLink(group, title, yLabel) { const dashboard = this.currentDashboard || this.firstDashboard.path; - const params = { dashboard, group, title, y_label: yLabel }; + const params = _.pick({ dashboard, group, title, y_label: yLabel }, value => value != null); return mergeUrlParams(params, window.location.href); }, - // TODO: END hideAddMetricModal() { this.$refs.addMetricModal.hide(); }, diff --git a/app/assets/javascripts/pipelines/components/pipeline_url.vue b/app/assets/javascripts/pipelines/components/pipeline_url.vue index e01080b04d6..4efc1d2408a 100644 --- a/app/assets/javascripts/pipelines/components/pipeline_url.vue +++ b/app/assets/javascripts/pipelines/components/pipeline_url.vue @@ -104,7 +104,7 @@ export default { v-gl-tooltip :title=" __( - 'The code of a detached pipeline is tested against the source branch instead of merged results', + 'Pipelines for merge requests are configured. A detached pipeline runs in the context of the merge request, and not against the merged result. Learn more on the documentation for Pipelines for Merged Results.', ) " class="js-pipeline-url-detached badge badge-info" diff --git a/app/assets/javascripts/vue_shared/components/file_row.vue b/app/assets/javascripts/vue_shared/components/file_row.vue index fe5289ff371..f49e69c473b 100644 --- a/app/assets/javascripts/vue_shared/components/file_row.vue +++ b/app/assets/javascripts/vue_shared/components/file_row.vue @@ -146,6 +146,7 @@ export default { <span ref="textOutput" :style="levelIndentation" class="file-row-name str-truncated"> <file-icon v-if="!showChangedIcon || file.type === 'tree'" + class="file-row-icon" :file-name="file.name" :loading="file.loading" :folder="isTree" @@ -223,13 +224,8 @@ export default { white-space: nowrap; } -.file-row-name svg { +.file-row-name .file-row-icon { margin-right: 2px; vertical-align: middle; } - -.file-row-name .loading-container { - display: inline-block; - margin-right: 4px; -} </style> diff --git a/app/assets/javascripts/vue_shared/directives/autofocusonshow.js b/app/assets/javascripts/vue_shared/directives/autofocusonshow.js new file mode 100644 index 00000000000..4659ec20ceb --- /dev/null +++ b/app/assets/javascripts/vue_shared/directives/autofocusonshow.js @@ -0,0 +1,39 @@ +/** + * Input/Textarea Autofocus Directive for Vue + */ +export default { + /** + * Set focus when element is rendered, but + * is not visible, using IntersectionObserver + * + * @param {Element} el Target element + */ + inserted(el) { + if ('IntersectionObserver' in window) { + // Element visibility is dynamic, so we attach observer + el.visibilityObserver = new IntersectionObserver(entries => { + entries.forEach(entry => { + // Combining `intersectionRatio > 0` and + // element's `offsetParent` presence will + // deteremine if element is truely visible + if (entry.intersectionRatio > 0 && entry.target.offsetParent) { + entry.target.focus(); + } + }); + }); + + // Bind the observer. + el.visibilityObserver.observe(el, { root: document.documentElement }); + } + }, + /** + * Detach observer on unbind hook. + * + * @param {Element} el Target element + */ + unbind(el) { + if (el.visibilityObserver) { + el.visibilityObserver.disconnect(); + } + }, +}; diff --git a/app/assets/stylesheets/framework/badges.scss b/app/assets/stylesheets/framework/badges.scss index c6060161dec..c036267a7c8 100644 --- a/app/assets/stylesheets/framework/badges.scss +++ b/app/assets/stylesheets/framework/badges.scss @@ -1,6 +1,6 @@ .badge.badge-pill { font-weight: $gl-font-weight-normal; background-color: $badge-bg; - color: $gl-text-color-secondary; + color: $gray-800; vertical-align: baseline; } diff --git a/app/assets/stylesheets/framework/common.scss b/app/assets/stylesheets/framework/common.scss index f384a49e0ae..e9218dcec67 100644 --- a/app/assets/stylesheets/framework/common.scss +++ b/app/assets/stylesheets/framework/common.scss @@ -438,6 +438,7 @@ img.emoji { .w-3rem { width: 3rem; } .h-12em { height: 12em; } +.h-32-px { height: 32px;} .mw-460 { max-width: 460px; } .mw-6em { max-width: 6em; } diff --git a/app/assets/stylesheets/framework/header.scss b/app/assets/stylesheets/framework/header.scss index 1bc597bd4ae..ca737c53318 100644 --- a/app/assets/stylesheets/framework/header.scss +++ b/app/assets/stylesheets/framework/header.scss @@ -131,7 +131,6 @@ > li:not(.d-none) a { @include media-breakpoint-down(xs) { margin-left: 0; - min-width: 100%; } } } @@ -233,7 +232,6 @@ .impersonation-btn, .impersonation-btn:hover { background-color: $white-light; - margin-left: 0; border-top-left-radius: 0; border-bottom-left-radius: 0; diff --git a/app/assets/stylesheets/highlight/common.scss b/app/assets/stylesheets/highlight/common.scss index ac3214a07d9..bdeac7e97c0 100644 --- a/app/assets/stylesheets/highlight/common.scss +++ b/app/assets/stylesheets/highlight/common.scss @@ -16,3 +16,16 @@ color: $dark-diff-match-bg; background: $dark-diff-match-color; } + +@mixin diff-expansion($background, $border, $link) { + background-color: $background; + + td { + border-top: 1px solid $border; + border-bottom: 1px solid $border; + } + + a { + color: $link; + } +} diff --git a/app/assets/stylesheets/highlight/themes/dark.scss b/app/assets/stylesheets/highlight/themes/dark.scss index 16893dd047e..cbce0ba3f1e 100644 --- a/app/assets/stylesheets/highlight/themes/dark.scss +++ b/app/assets/stylesheets/highlight/themes/dark.scss @@ -111,6 +111,10 @@ $dark-il: #de935f; color: $dark-line-color; } + .line_expansion { + @include diff-expansion($dark-main-bg, $dark-border, $dark-na); + } + // Diff line .line_holder { &.match .line_content, diff --git a/app/assets/stylesheets/highlight/themes/monokai.scss b/app/assets/stylesheets/highlight/themes/monokai.scss index 37fe61b925c..1b61ffa37e3 100644 --- a/app/assets/stylesheets/highlight/themes/monokai.scss +++ b/app/assets/stylesheets/highlight/themes/monokai.scss @@ -111,6 +111,10 @@ $monokai-gi: #a6e22e; color: $monokai-text-color; } + .line_expansion { + @include diff-expansion($monokai-bg, $monokai-border, $monokai-k); + } + // Diff line .line_holder { &.match .line_content, diff --git a/app/assets/stylesheets/highlight/themes/none.scss b/app/assets/stylesheets/highlight/themes/none.scss index b4217aac37a..a7ede266fb5 100644 --- a/app/assets/stylesheets/highlight/themes/none.scss +++ b/app/assets/stylesheets/highlight/themes/none.scss @@ -34,8 +34,11 @@ color: $gl-text-color; } -// Diff line + .line_expansion { + @include diff-expansion($gray-light, $white-normal, $gl-text-color); + } + // Diff line $none-over-bg: #ded7fc; $none-expanded-border: #e0e0e0; $none-expanded-bg: #e0e0e0; diff --git a/app/assets/stylesheets/highlight/themes/solarized-dark.scss b/app/assets/stylesheets/highlight/themes/solarized-dark.scss index a4e9eda22c9..6569f3abc8b 100644 --- a/app/assets/stylesheets/highlight/themes/solarized-dark.scss +++ b/app/assets/stylesheets/highlight/themes/solarized-dark.scss @@ -115,6 +115,10 @@ $solarized-dark-il: #2aa198; color: $solarized-dark-pre-color; } + .line_expansion { + @include diff-expansion($solarized-dark-line-bg, $solarized-dark-border, $solarized-dark-kd); + } + // Diff line .line_holder { &.match .line_content, diff --git a/app/assets/stylesheets/highlight/themes/solarized-light.scss b/app/assets/stylesheets/highlight/themes/solarized-light.scss index b604d1ccb6c..4e74a9ea50a 100644 --- a/app/assets/stylesheets/highlight/themes/solarized-light.scss +++ b/app/assets/stylesheets/highlight/themes/solarized-light.scss @@ -122,6 +122,10 @@ $solarized-light-il: #2aa198; color: $solarized-light-pre-color; } + .line_expansion { + @include diff-expansion($solarized-light-line-bg, $solarized-light-border, $solarized-light-kd); + } + // Diff line .line_holder { &.match .line_content, diff --git a/app/assets/stylesheets/highlight/white_base.scss b/app/assets/stylesheets/highlight/white_base.scss index b3974df8639..973f94c63aa 100644 --- a/app/assets/stylesheets/highlight/white_base.scss +++ b/app/assets/stylesheets/highlight/white_base.scss @@ -101,24 +101,8 @@ pre.code, color: $white-code-color; } -// Expansion line .line_expansion { - background-color: $gray-light; - - td { - border-top: 1px solid $border-color; - border-bottom: 1px solid $border-color; - text-align: center; - } - - a { - color: $blue-600; - } - - .unfold-icon { - display: inline-block; - padding: 8px 0; - } + @include diff-expansion($gray-light, $border-color, $blue-600); } // Diff line diff --git a/app/assets/stylesheets/pages/reports.scss b/app/assets/stylesheets/pages/reports.scss index 85e9f303dde..0fbf7033aa5 100644 --- a/app/assets/stylesheets/pages/reports.scss +++ b/app/assets/stylesheets/pages/reports.scss @@ -48,11 +48,6 @@ padding: $gl-padding-top $gl-padding; border-top: 1px solid $border-color; } - - .report-block-list-icon .loading-container { - position: relative; - left: -2px; - } } .report-block-container { diff --git a/app/controllers/concerns/invisible_captcha.rb b/app/controllers/concerns/invisible_captcha.rb index c9f66e5c194..45c0a5c58ef 100644 --- a/app/controllers/concerns/invisible_captcha.rb +++ b/app/controllers/concerns/invisible_captcha.rb @@ -41,9 +41,9 @@ module InvisibleCaptcha request_information = { message: message, env: :invisible_captcha_signup_bot_detected, - ip: request.ip, + remote_ip: request.ip, request_method: request.request_method, - fullpath: request.fullpath + path: request.fullpath } Gitlab::AuthLogger.error(request_information) diff --git a/app/controllers/projects/blob_controller.rb b/app/controllers/projects/blob_controller.rb index b04ffe80db4..4125f44d00a 100644 --- a/app/controllers/projects/blob_controller.rb +++ b/app/controllers/projects/blob_controller.rb @@ -92,7 +92,7 @@ class Projects::BlobController < Projects::ApplicationController def diff apply_diff_view_cookie! - @form = Blobs::UnfoldPresenter.new(blob, params.to_unsafe_h) + @form = Blobs::UnfoldPresenter.new(blob, diff_params) # keep only json rendering when # https://gitlab.com/gitlab-org/gitlab-ce/issues/44988 is done @@ -239,4 +239,8 @@ class Projects::BlobController < Projects::ApplicationController def tree_path @path.rpartition('/').first end + + def diff_params + params.permit(:full, :since, :to, :bottom, :unfold, :offset, :indent) + end end diff --git a/app/controllers/projects/starrers_controller.rb b/app/controllers/projects/starrers_controller.rb index e4093bed0ef..4efe956e973 100644 --- a/app/controllers/projects/starrers_controller.rb +++ b/app/controllers/projects/starrers_controller.rb @@ -5,11 +5,11 @@ class Projects::StarrersController < Projects::ApplicationController def index @starrers = UsersStarProjectsFinder.new(@project, params, current_user: @current_user).execute + @sort = params[:sort].presence || sort_value_name + @starrers = @starrers.preload_users.sort_by_attribute(@sort).page(params[:page]) @public_count = @project.starrers.with_public_profile.size @total_count = @project.starrers.size @private_count = @total_count - @public_count - @sort = params[:sort].presence || sort_value_name - @starrers = @starrers.sort_by_attribute(@sort).page(params[:page]) end private diff --git a/app/models/repository.rb b/app/models/repository.rb index 6f63cd32da4..b957b9b0bdd 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -239,13 +239,13 @@ class Repository def branch_exists?(branch_name) return false unless raw_repository - branch_names.include?(branch_name) + branch_names_include?(branch_name) end def tag_exists?(tag_name) return false unless raw_repository - tag_names.include?(tag_name) + tag_names_include?(tag_name) end def ref_exists?(ref) @@ -565,10 +565,10 @@ class Repository end delegate :branch_names, to: :raw_repository - cache_method :branch_names, fallback: [] + cache_method_as_redis_set :branch_names, fallback: [] delegate :tag_names, to: :raw_repository - cache_method :tag_names, fallback: [] + cache_method_as_redis_set :tag_names, fallback: [] delegate :branch_count, :tag_count, :has_visible_content?, to: :raw_repository cache_method :branch_count, fallback: 0 @@ -1130,6 +1130,10 @@ class Repository @cache ||= Gitlab::RepositoryCache.new(self) end + def redis_set_cache + @redis_set_cache ||= Gitlab::RepositorySetCache.new(self) + end + def request_store_cache @request_store_cache ||= Gitlab::RepositoryCache.new(self, backend: Gitlab::SafeRequestStore) end diff --git a/app/models/users_star_project.rb b/app/models/users_star_project.rb index 3c7a805cc5c..c633e2d8b3d 100644 --- a/app/models/users_star_project.rb +++ b/app/models/users_star_project.rb @@ -17,6 +17,7 @@ class UsersStarProject < ApplicationRecord scope :by_project, -> (project) { where(project_id: project.id) } scope :with_visible_profile, -> (user) { joins(:user).merge(User.with_visible_profile(user)) } scope :with_public_profile, -> { joins(:user).merge(User.with_public_profile) } + scope :preload_users, -> { preload(:user) } class << self def sort_by_attribute(method) diff --git a/app/presenters/blobs/unfold_presenter.rb b/app/presenters/blobs/unfold_presenter.rb index 4c6dd6895cf..a256dd05a4d 100644 --- a/app/presenters/blobs/unfold_presenter.rb +++ b/app/presenters/blobs/unfold_presenter.rb @@ -1,30 +1,34 @@ # frozen_string_literal: true -require 'gt_one_coercion' - module Blobs class UnfoldPresenter < BlobPresenter - include Virtus.model + include ActiveModel::Attributes + include ActiveModel::AttributeAssignment include Gitlab::Utils::StrongMemoize - attribute :full, Boolean, default: false - attribute :since, GtOneCoercion - attribute :to, Integer - attribute :bottom, Boolean - attribute :unfold, Boolean, default: true - attribute :offset, Integer - attribute :indent, Integer, default: 0 + attribute :full, :boolean, default: false + attribute :since, :integer, default: 1 + attribute :to, :integer, default: 1 + attribute :bottom, :boolean, default: false + attribute :unfold, :boolean, default: true + attribute :offset, :integer, default: 0 + attribute :indent, :integer, default: 0 + + alias_method :full?, :full + alias_method :bottom?, :bottom + alias_method :unfold?, :unfold def initialize(blob, params) + super(blob) + self.attributes = params + # Load all blob data first as we need to ensure they're all loaded first # so we can accurately show the rest of the diff when unfolding. load_all_blob_data - @subject = blob @all_lines = blob.data.lines - super(params) - self.attributes = prepare_attributes + handle_full_or_end! end # Returns an array of Gitlab::Diff::Line with match line added @@ -56,21 +60,18 @@ module Blobs private - def prepare_attributes - return attributes unless full? || to == -1 + def handle_full_or_end! + return unless full? || to == -1 - full_opts = { - since: 1, + self.since = 1 if full? + + self.attributes = { to: all_lines_size, bottom: false, unfold: false, offset: 0, indent: 0 } - - return full_opts if full? - - full_opts.merge(attributes.slice(:since)) end def all_lines_size diff --git a/app/views/layouts/header/_default.html.haml b/app/views/layouts/header/_default.html.haml index 89f99472270..14c7b2428b2 100644 --- a/app/views/layouts/header/_default.html.haml +++ b/app/views/layouts/header/_default.html.haml @@ -4,6 +4,7 @@ - search_path_url = search_path(group_id: group.id) - else - search_path_url = search_path +- has_impersonation_link = header_link?(:admin_impersonation) %header.navbar.navbar-gitlab.navbar-expand-sm.js-navbar{ data: { qa_selector: 'navbar' } } %a.sr-only.gl-accessibility{ href: "#content-body", tabindex: "1" } Skip to content @@ -64,14 +65,14 @@ .dropdown-menu.dropdown-menu-right = render 'layouts/header/help_dropdown' - if header_link?(:user_dropdown) - %li.nav-item.header-user.dropdown{ data: { track_label: "profile_dropdown", track_event: "click_dropdown", track_value: "", qa_selector: 'user_menu' } } + %li.nav-item.header-user.dropdown{ data: { track_label: "profile_dropdown", track_event: "click_dropdown", track_value: "", qa_selector: 'user_menu' }, class: ('mr-0' if has_impersonation_link) } = link_to current_user, class: user_dropdown_class, data: { toggle: "dropdown" } do = image_tag avatar_icon_for_user(current_user, 23), width: 23, height: 23, class: "header-user-avatar qa-user-avatar" = sprite_icon('angle-down', css_class: 'caret-down') .dropdown-menu.dropdown-menu-right = render 'layouts/header/current_user_dropdown' - - if header_link?(:admin_impersonation) - %li.nav-item.impersonation + - if has_impersonation_link + %li.nav-item.impersonation.ml-0 = link_to admin_impersonation_path, class: 'nav-link impersonation-btn', method: :delete, title: _('Stop impersonation'), aria: { label: _('Stop impersonation') }, data: { toggle: 'tooltip', placement: 'bottom', container: 'body' } do = icon('user-secret') - if header_link?(:sign_in) diff --git a/app/views/projects/pipelines/_info.html.haml b/app/views/projects/pipelines/_info.html.haml index 2b56ada8b73..9614f33fe2f 100644 --- a/app/views/projects/pipelines/_info.html.haml +++ b/app/views/projects/pipelines/_info.html.haml @@ -43,7 +43,7 @@ } } Auto DevOps - if @pipeline.detached_merge_request_pipeline? - %span.js-pipeline-url-mergerequest.badge.badge-info.has-tooltip{ title: "The code of a detached pipeline is tested against the source branch instead of merged results" } + %span.js-pipeline-url-mergerequest.badge.badge-info.has-tooltip{ title: _('Pipelines for merge requests are configured. A detached pipeline runs in the context of the merge request, and not against the merged result. Learn more on the documentation for Pipelines for Merged Results.') } detached - if @pipeline.stuck? %span.js-pipeline-url-stuck.badge.badge-warning diff --git a/changelogs/unreleased/62373-badge-counter-very-low-contrast-between-foreground-and-background-c.yml b/changelogs/unreleased/62373-badge-counter-very-low-contrast-between-foreground-and-background-c.yml new file mode 100644 index 00000000000..12b19da1868 --- /dev/null +++ b/changelogs/unreleased/62373-badge-counter-very-low-contrast-between-foreground-and-background-c.yml @@ -0,0 +1,6 @@ +--- +title: 'Resolve Badge counter: Very low contrast between foreground and background + colors' +merge_request: 31922 +author: +type: other diff --git a/changelogs/unreleased/64251-branch-name-set-cache.yml b/changelogs/unreleased/64251-branch-name-set-cache.yml new file mode 100644 index 00000000000..6ce4bdf5e43 --- /dev/null +++ b/changelogs/unreleased/64251-branch-name-set-cache.yml @@ -0,0 +1,5 @@ +--- +title: Cache branch and tag names as Redis sets +merge_request: 30476 +author: +type: performance diff --git a/changelogs/unreleased/66061-update-tooltip-of-detached-label-state.yml b/changelogs/unreleased/66061-update-tooltip-of-detached-label-state.yml new file mode 100644 index 00000000000..826d5548999 --- /dev/null +++ b/changelogs/unreleased/66061-update-tooltip-of-detached-label-state.yml @@ -0,0 +1,5 @@ +--- +title: Updates tooltip of 'detached' label/state +merge_request: +author: +type: other diff --git a/changelogs/unreleased/66066-dark-theme-style-for-expansion-on-mr-diffs.yml b/changelogs/unreleased/66066-dark-theme-style-for-expansion-on-mr-diffs.yml new file mode 100644 index 00000000000..13607ae938a --- /dev/null +++ b/changelogs/unreleased/66066-dark-theme-style-for-expansion-on-mr-diffs.yml @@ -0,0 +1,5 @@ +--- +title: Add syntax highlighting for line expansion +merge_request: 31821 +author: +type: fixed diff --git a/changelogs/unreleased/66161-replace-expand-icons.yml b/changelogs/unreleased/66161-replace-expand-icons.yml new file mode 100644 index 00000000000..e28e01108a8 --- /dev/null +++ b/changelogs/unreleased/66161-replace-expand-icons.yml @@ -0,0 +1,5 @@ +--- +title: Replaced expand diff icons +merge_request: 31907 +author: +type: changed diff --git a/changelogs/unreleased/an-fix-sidekiq-histogram-buckets.yml b/changelogs/unreleased/an-fix-sidekiq-histogram-buckets.yml new file mode 100644 index 00000000000..696b8f3987e --- /dev/null +++ b/changelogs/unreleased/an-fix-sidekiq-histogram-buckets.yml @@ -0,0 +1,5 @@ +--- +title: Allow latency measurements of sidekiq jobs taking > 2.5s +merge_request: 32001 +author: +type: fixed diff --git a/changelogs/unreleased/bvl-mr-commit-note-counter.yml b/changelogs/unreleased/bvl-mr-commit-note-counter.yml new file mode 100644 index 00000000000..0e9becbd31e --- /dev/null +++ b/changelogs/unreleased/bvl-mr-commit-note-counter.yml @@ -0,0 +1,5 @@ +--- +title: Count comments on commits and merge requests +merge_request: 31912 +author: +type: other diff --git a/changelogs/unreleased/ci-config-on-policy.yml b/changelogs/unreleased/ci-config-on-policy.yml new file mode 100644 index 00000000000..d9804f0323a --- /dev/null +++ b/changelogs/unreleased/ci-config-on-policy.yml @@ -0,0 +1,5 @@ +--- +title: Introduced Build::Rules configuration for Ci::Build +merge_request: 29011 +author: +type: added diff --git a/changelogs/unreleased/clean-obsolete-css.yml b/changelogs/unreleased/clean-obsolete-css.yml new file mode 100644 index 00000000000..d9716d16762 --- /dev/null +++ b/changelogs/unreleased/clean-obsolete-css.yml @@ -0,0 +1,5 @@ +--- +title: Fix MR reports section loading icon alignment +merge_request: 31897 +author: +type: fixed diff --git a/changelogs/unreleased/fe-fix-merge-url-params-with-plus.yml b/changelogs/unreleased/fe-fix-merge-url-params-with-plus.yml new file mode 100644 index 00000000000..7ca8ae0a8f6 --- /dev/null +++ b/changelogs/unreleased/fe-fix-merge-url-params-with-plus.yml @@ -0,0 +1,5 @@ +--- +title: Fix search preserving space when change branch +merge_request: 31973 +author: minghuan lei +type: fixed diff --git a/changelogs/unreleased/fix-file-row-styling.yml b/changelogs/unreleased/fix-file-row-styling.yml new file mode 100644 index 00000000000..a4427fdd48f --- /dev/null +++ b/changelogs/unreleased/fix-file-row-styling.yml @@ -0,0 +1,5 @@ +--- +title: Fix loading icon causing text to jump in file row of Web IDE +merge_request: 31884 +author: +type: fixed diff --git a/changelogs/unreleased/pb-update-gitlab-shell-9-4-0.yml b/changelogs/unreleased/pb-update-gitlab-shell-9-4-0.yml new file mode 100644 index 00000000000..81db7bb4900 --- /dev/null +++ b/changelogs/unreleased/pb-update-gitlab-shell-9-4-0.yml @@ -0,0 +1,5 @@ +--- +title: Update to GitLab Shell v9.4.0 +merge_request: 32009 +author: +type: other diff --git a/changelogs/unreleased/remove-margin-from-user-header.yml b/changelogs/unreleased/remove-margin-from-user-header.yml new file mode 100644 index 00000000000..31200d13c93 --- /dev/null +++ b/changelogs/unreleased/remove-margin-from-user-header.yml @@ -0,0 +1,5 @@ +--- +title: Remove margin from user header +merge_request: 30878 +author: lucyfox +type: fixed diff --git a/changelogs/unreleased/sh-fix-issues-api-gitaly-nplusone.yml b/changelogs/unreleased/sh-fix-issues-api-gitaly-nplusone.yml new file mode 100644 index 00000000000..3177cb8d18c --- /dev/null +++ b/changelogs/unreleased/sh-fix-issues-api-gitaly-nplusone.yml @@ -0,0 +1,5 @@ +--- +title: Fix Gitaly N+1 calls with listing issues/MRs via API +merge_request: 31938 +author: +type: performance diff --git a/changelogs/unreleased/tr-param-undefined-fix.yml b/changelogs/unreleased/tr-param-undefined-fix.yml new file mode 100644 index 00000000000..0a9051485bd --- /dev/null +++ b/changelogs/unreleased/tr-param-undefined-fix.yml @@ -0,0 +1,5 @@ +--- +title: Fix for embedded metrics undefined params +merge_request: 31975 +author: +type: fixed diff --git a/changelogs/unreleased/update-babel-to-7-5-5.yml b/changelogs/unreleased/update-babel-to-7-5-5.yml new file mode 100644 index 00000000000..c498e2adfe8 --- /dev/null +++ b/changelogs/unreleased/update-babel-to-7-5-5.yml @@ -0,0 +1,5 @@ +--- +title: Upgrade babel to 7.5.5 +merge_request: 31819 +author: Takuya Noguchi +type: other diff --git a/config/initializers/rack_attack_logging.rb b/config/initializers/rack_attack_logging.rb index 7eb34bd69e5..b43fff24bb0 100644 --- a/config/initializers/rack_attack_logging.rb +++ b/config/initializers/rack_attack_logging.rb @@ -7,9 +7,9 @@ ActiveSupport::Notifications.subscribe('rack.attack') do |name, start, finish, r rack_attack_info = { message: 'Rack_Attack', env: req.env['rack.attack.match_type'], - ip: req.ip, + remote_ip: req.ip, request_method: req.request_method, - fullpath: req.fullpath + path: req.fullpath } if %w(throttle_authenticated_api throttle_authenticated_web).include? req.env['rack.attack.matched'] diff --git a/config/routes.rb b/config/routes.rb index fdef31429f3..d633228a495 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -109,6 +109,7 @@ Rails.application.routes.draw do Gitlab.ee do draw :smartcard draw :jira_connect + draw :username end Gitlab.ee do diff --git a/config/sidekiq_queues.yml b/config/sidekiq_queues.yml index c7586aa1e38..ea165508d29 100644 --- a/config/sidekiq_queues.yml +++ b/config/sidekiq_queues.yml @@ -113,3 +113,4 @@ - [elastic_namespace_indexer, 1] - [export_csv, 1] - [incident_management, 2] + - [jira_connect, 1] diff --git a/db/fixtures/development/14_pipelines.rb b/db/fixtures/development/14_pipelines.rb index 05bda7d3672..5c8b681fa92 100644 --- a/db/fixtures/development/14_pipelines.rb +++ b/db/fixtures/development/14_pipelines.rb @@ -1,7 +1,7 @@ require './spec/support/sidekiq' class Gitlab::Seeder::Pipelines - STAGES = %w[build test security deploy notify] + STAGES = %w[build test deploy notify] BUILDS = [ # build stage { name: 'build:linux', stage: 'build', status: :success, @@ -31,16 +31,6 @@ class Gitlab::Seeder::Pipelines { name: 'spinach:osx', stage: 'test', status: :failed, allow_failure: true, queued_at: 8.hour.ago, started_at: 8.hour.ago, finished_at: 7.hour.ago }, - # security stage - { name: 'dast', stage: 'security', status: :success, - queued_at: 8.hour.ago, started_at: 8.hour.ago, finished_at: 7.hour.ago }, - { name: 'sast', stage: 'security', status: :success, - queued_at: 8.hour.ago, started_at: 8.hour.ago, finished_at: 7.hour.ago }, - { name: 'dependency_scanning', stage: 'security', status: :success, - queued_at: 8.hour.ago, started_at: 8.hour.ago, finished_at: 7.hour.ago }, - { name: 'container_scanning', stage: 'security', status: :success, - queued_at: 8.hour.ago, started_at: 8.hour.ago, finished_at: 7.hour.ago }, - # deploy stage { name: 'staging', stage: 'deploy', environment: 'staging', status_event: :success, options: { environment: { action: 'start', on_stop: 'stop staging' } }, @@ -127,11 +117,6 @@ class Gitlab::Seeder::Pipelines setup_artifacts(build) setup_test_reports(build) - if build.ref == build.project.default_branch - setup_security_reports_file(build) - else - setup_security_reports_legacy_archive(build) - end setup_build_log(build) build.project.environments. @@ -167,55 +152,6 @@ class Gitlab::Seeder::Pipelines end end - def setup_security_reports_file(build) - return unless build.stage == "security" - - # we have two sources: master and feature-branch - branch_name = build.ref == build.project.default_branch ? - 'master' : 'feature-branch' - - artifacts_cache_file(security_reports_path(branch_name, build.name)) do |file| - build.job_artifacts.build( - project: build.project, - file_type: build.name, - file_format: :raw, - file: file) - end - end - - def setup_security_reports_legacy_archive(build) - return unless build.stage == "security" - - # we have two sources: master and feature-branch - branch_name = build.ref == build.project.default_branch ? - 'master' : 'feature-branch' - - artifacts_cache_file(security_reports_archive_path(branch_name)) do |file| - build.job_artifacts.build( - project: build.project, - file_type: :archive, - file_format: :zip, - file: file) - end - - # assign dummy metadata - artifacts_cache_file(artifacts_metadata_path) do |file| - build.job_artifacts.build( - project: build.project, - file_type: :metadata, - file_format: :gzip, - file: file) - end - - build.options = { - artifacts: { - paths: [ - Ci::JobArtifact::DEFAULT_FILE_NAMES.fetch(build.name.to_sym) - ] - } - } - end - def setup_build_log(build) if %w(running success failed).include?(build.status) build.trace.set(FFaker::Lorem.paragraphs(6).join("\n\n")) @@ -267,15 +203,6 @@ class Gitlab::Seeder::Pipelines Rails.root + 'spec/fixtures/junit/junit.xml.gz' end - def security_reports_archive_path(branch) - Rails.root.join('spec', 'fixtures', 'security-reports', branch + '.zip') - end - - def security_reports_path(branch, name) - file_name = Ci::JobArtifact::DEFAULT_FILE_NAMES.fetch(name.to_sym) - Rails.root.join('spec', 'fixtures', 'security-reports', branch, file_name) - end - def artifacts_cache_file(file_path) file = Tempfile.new("artifacts") file.close diff --git a/doc/administration/geo/disaster_recovery/index.md b/doc/administration/geo/disaster_recovery/index.md index d44e141b66b..ba95843b0b0 100644 --- a/doc/administration/geo/disaster_recovery/index.md +++ b/doc/administration/geo/disaster_recovery/index.md @@ -1,4 +1,4 @@ -# Disaster Recovery **(PREMIUM ONLY)** +# Disaster Recovery (Geo) **(PREMIUM ONLY)** Geo replicates your database, your Git repositories, and few other assets. We will support and replicate more data in the future, that will enable you to diff --git a/doc/administration/geo/replication/index.md b/doc/administration/geo/replication/index.md index 5aedb665935..dbd466b906d 100644 --- a/doc/administration/geo/replication/index.md +++ b/doc/administration/geo/replication/index.md @@ -1,4 +1,4 @@ -# Geo Replication **(PREMIUM ONLY)** +# Replication (Geo) **(PREMIUM ONLY)** > - Introduced in GitLab Enterprise Edition 8.9. > - Using Geo in combination with @@ -6,7 +6,7 @@ > is considered **Generally Available** (GA) in > [GitLab Premium](https://about.gitlab.com/pricing/) 10.4. -Geo is the solution for widely distributed development teams. +Replication with Geo is the solution for widely distributed development teams. ## Overview diff --git a/doc/administration/logs.md b/doc/administration/logs.md index a57ef8ddc7d..9030c941cad 100644 --- a/doc/administration/logs.md +++ b/doc/administration/logs.md @@ -88,7 +88,7 @@ Introduced in GitLab 10.0, this file lives in It helps you see requests made directly to the API. For example: ```json -{"time":"2018-10-29T12:49:42.123Z","severity":"INFO","duration":709.08,"db":14.59,"view":694.49,"status":200,"method":"GET","path":"/api/v4/projects","params":[{"key":"action","value":"git-upload-pack"},{"key":"changes","value":"_any"},{"key":"key_id","value":"secret"},{"key":"secret_token","value":"[FILTERED]"}],"host":"localhost","ip":"::1","ua":"Ruby","route":"/api/:version/projects","user_id":1,"username":"root","queue_duration":100.31,"gitaly_calls":30,"gitaly_duration":5.36} +{"time":"2018-10-29T12:49:42.123Z","severity":"INFO","duration":709.08,"db":14.59,"view":694.49,"status":200,"method":"GET","path":"/api/v4/projects","params":[{"key":"action","value":"git-upload-pack"},{"key":"changes","value":"_any"},{"key":"key_id","value":"secret"},{"key":"secret_token","value":"[FILTERED]"}],"host":"localhost","remote_ip":"::1","ua":"Ruby","route":"/api/:version/projects","user_id":1,"username":"root","queue_duration":100.31,"gitaly_calls":30,"gitaly_duration":5.36} ``` This entry above shows an access to an internal endpoint to check whether an diff --git a/doc/api/issues.md b/doc/api/issues.md index ebb1ebb6815..4f2b4a966c9 100644 --- a/doc/api/issues.md +++ b/doc/api/issues.md @@ -136,7 +136,6 @@ Example response: "award_emoji":"http://example.com/api/v4/projects/1/issues/76/award_emoji", "project":"http://example.com/api/v4/projects/1" }, - "subscribed": false, "task_completion_status":{ "count":0, "completed_count":0 @@ -441,7 +440,6 @@ Example response: "award_emoji":"http://example.com/api/v4/projects/4/issues/41/award_emoji", "project":"http://example.com/api/v4/projects/4" }, - "subscribed": false, "task_completion_status":{ "count":0, "completed_count":0 diff --git a/doc/ci/docker/using_docker_images.md b/doc/ci/docker/using_docker_images.md index d5056568dff..489791141ed 100644 --- a/doc/ci/docker/using_docker_images.md +++ b/doc/ci/docker/using_docker_images.md @@ -495,14 +495,6 @@ that runner. ## Define an image from a private Container Registry -> **Notes:** -> -> - This feature requires GitLab Runner **1.8** or higher -> - For GitLab Runner versions **>= 0.6, <1.8** there was a partial -> support for using private registries, which required manual configuration -> of credentials on runner's host. We recommend to upgrade your Runner to -> at least version **1.8** if you want to use private registries. - To access private container registries, the GitLab Runner process can use: - [Statically defined credentials](#using-statically-defined-credentials). That is, a username and password for a specific registry. @@ -525,6 +517,17 @@ it's provided as an environment variable. This is because GitLab Runnner uses ** `config.toml` configuration and doesn't interpolate **ANY** environment variables at runtime. +### Requirements and limitations + +- This feature requires GitLab Runner **1.8** or higher. +- For GitLab Runner versions **>= 0.6, <1.8** there was a partial + support for using private registries, which required manual configuration + of credentials on runner's host. We recommend to upgrade your Runner to + at least version **1.8** if you want to use private registries. +- Not available for [Kubernetes executor](https://docs.gitlab.com/runner/executors/kubernetes.html), + follow <https://gitlab.com/gitlab-org/gitlab-runner/issues/2673> for + details. + ### Using statically-defined credentials There are two approaches that you can take in order to access a diff --git a/doc/ci/ssh_keys/README.md b/doc/ci/ssh_keys/README.md index d9f022a7125..b6aebd3bd78 100644 --- a/doc/ci/ssh_keys/README.md +++ b/doc/ci/ssh_keys/README.md @@ -76,7 +76,7 @@ to access it. This is where an SSH key pair comes in handy. ## without extra base64 encoding. ## https://gitlab.com/gitlab-examples/ssh-private-key/issues/1#note_48526556 ## - - echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add - > /dev/null + - echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add - ## ## Create the SSH directory and give it the right permissions diff --git a/doc/ci/variables/README.md b/doc/ci/variables/README.md index d741482b662..5a15b907da0 100644 --- a/doc/ci/variables/README.md +++ b/doc/ci/variables/README.md @@ -94,7 +94,10 @@ This means that the value of the variable will be hidden in job logs, though it must match certain requirements to do so: - The value must be in a single line. -- The value must only consist of characters from the Base64 alphabet ([RFC4648](https://tools.ietf.org/html/rfc4648)) with the addition of `@` and `:`. +- The value must only consist of characters from the Base64 alphabet (RFC4648). + + [In GitLab 12.2](https://gitlab.com/gitlab-org/gitlab-ce/issues/63043) + and newer, `@` and `:` are also valid values. - The value must be at least 8 characters long. - The value must not use variables. @@ -509,7 +512,7 @@ Below you can find supported syntax reference: 1. Checking for an empty variable Examples: - + - `$VARIABLE == ""` - `$VARIABLE != ""` (introduced in GitLab 11.11) diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md index 2be93433b36..76b73729d0b 100644 --- a/doc/ci/yaml/README.md +++ b/doc/ci/yaml/README.md @@ -1721,7 +1721,7 @@ This example creates three paths of execution: 1. If `needs:` is set to point to a job that is not instantiated because of `only/except` rules or otherwise does not exist, the job will fail. -1. Note that one day one of the launch, we are temporarily limiting the +1. Note that on day one of the launch, we are temporarily limiting the maximum number of jobs that a single job can need in the `needs:` array. Track our [infrastructure issue](https://gitlab.com/gitlab-com/gl-infra/infrastructure/issues/7541) for details on the current limit. diff --git a/doc/development/automatic_ce_ee_merge.md b/doc/development/automatic_ce_ee_merge.md index 98b8a48abf4..001a92790e1 100644 --- a/doc/development/automatic_ce_ee_merge.md +++ b/doc/development/automatic_ce_ee_merge.md @@ -200,7 +200,7 @@ code. ### Why merge automatically? As we work towards continuous deployments and a single repository for both CE -and EE, we need to first make sure that all CE changes make their way into CE as +and EE, we need to first make sure that all CE changes make their way into EE as fast as possible. Past experiences and data have shown that periodic CE to EE merge requests do not scale, and often take a very long time to complete. For example, [in this diff --git a/doc/development/fe_guide/axios.md b/doc/development/fe_guide/axios.md index 09b4a3c3d96..6e7cf523f36 100644 --- a/doc/development/fe_guide/axios.md +++ b/doc/development/fe_guide/axios.md @@ -38,7 +38,7 @@ Advantages over [`spyOn()`]: - no need to create response objects - does not allow call through (which we want to avoid) -- simple API to test error cases +- simple API to test error cases - provides `replyOnce()` to allow for different responses We have also decided against using [axios interceptors] because they are not suitable for mocking. diff --git a/doc/development/fe_guide/style_guide_js.md b/doc/development/fe_guide/style_guide_js.md index d3fa350b847..125b11afcd0 100644 --- a/doc/development/fe_guide/style_guide_js.md +++ b/doc/development/fe_guide/style_guide_js.md @@ -21,31 +21,31 @@ See [our current .eslintrc](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/ 1. **Never Ever EVER** disable eslint globally for a file ```javascript - // bad - /* eslint-disable */ + // bad + /* eslint-disable */ - // better - /* eslint-disable some-rule, some-other-rule */ + // better + /* eslint-disable some-rule, some-other-rule */ - // best - // nothing :) + // best + // nothing :) ``` 1. If you do need to disable a rule for a single violation, try to do it as locally as possible ```javascript - // bad - /* eslint-disable no-new */ + // bad + /* eslint-disable no-new */ - import Foo from 'foo'; + import Foo from 'foo'; - new Foo(); + new Foo(); - // better - import Foo from 'foo'; + // better + import Foo from 'foo'; - // eslint-disable-next-line no-new - new Foo(); + // eslint-disable-next-line no-new + new Foo(); ``` 1. There are few rules that we need to disable due to technical debt. Which are: @@ -56,16 +56,16 @@ See [our current .eslintrc](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/ followed by any global declarations, then a blank newline prior to any imports or code. ```javascript - // bad - /* global Foo */ - /* eslint-disable no-new */ - import Bar from './bar'; + // bad + /* global Foo */ + /* eslint-disable no-new */ + import Bar from './bar'; - // good - /* eslint-disable no-new */ - /* global Foo */ + // good + /* eslint-disable no-new */ + /* global Foo */ - import Bar from './bar'; + import Bar from './bar'; ``` 1. **Never** disable the `no-undef` rule. Declare globals with `/* global Foo */` instead. @@ -73,23 +73,23 @@ See [our current .eslintrc](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/ 1. When declaring multiple globals, always use one `/* global [name] */` line per variable. ```javascript - // bad - /* globals Flash, Cookies, jQuery */ + // bad + /* globals Flash, Cookies, jQuery */ - // good - /* global Flash */ - /* global Cookies */ - /* global jQuery */ + // good + /* global Flash */ + /* global Cookies */ + /* global jQuery */ ``` 1. Use up to 3 parameters for a function or class. If you need more accept an Object instead. ```javascript - // bad - fn(p1, p2, p3, p4) {} + // bad + fn(p1, p2, p3, p4) {} - // good - fn(options) {} + // good + fn(options) {} ``` #### Modules, Imports, and Exports @@ -97,32 +97,32 @@ See [our current .eslintrc](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/ 1. Use ES module syntax to import modules ```javascript - // bad - const SomeClass = require('some_class'); + // bad + const SomeClass = require('some_class'); - // good - import SomeClass from 'some_class'; + // good + import SomeClass from 'some_class'; - // bad - module.exports = SomeClass; + // bad + module.exports = SomeClass; - // good - export default SomeClass; + // good + export default SomeClass; ``` Import statements are following usual naming guidelines, for example object literals use camel case: ```javascript - // some_object file - export default { - key: 'value', - }; + // some_object file + export default { + key: 'value', + }; - // bad - import ObjectLiteral from 'some_object'; + // bad + import ObjectLiteral from 'some_object'; - // good - import objectLiteral from 'some_object'; + // good + import objectLiteral from 'some_object'; ``` 1. Relative paths: when importing a module in the same directory, a child @@ -171,22 +171,22 @@ See [our current .eslintrc](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/ 1. Avoid adding to the global namespace. ```javascript - // bad - window.MyClass = class { /* ... */ }; + // bad + window.MyClass = class { /* ... */ }; - // good - export default class MyClass { /* ... */ } + // good + export default class MyClass { /* ... */ } ``` 1. Side effects are forbidden in any script which contains export ```javascript - // bad - export default class MyClass { /* ... */ } + // bad + export default class MyClass { /* ... */ } - document.addEventListener("DOMContentLoaded", function(event) { - new MyClass(); - } + document.addEventListener("DOMContentLoaded", function(event) { + new MyClass(); + } ``` #### Data Mutation and Pure functions @@ -257,17 +257,17 @@ See [our current .eslintrc](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/ `.reduce` or `.filter` ```javascript - const users = [ { name: 'Foo' }, { name: 'Bar' } ]; + const users = [ { name: 'Foo' }, { name: 'Bar' } ]; - // bad - users.forEach((user, index) => { - user.id = index; - }); + // bad + users.forEach((user, index) => { + user.id = index; + }); - // good - const usersWithId = users.map((user, index) => { - return Object.assign({}, user, { id: index }); - }); + // good + const usersWithId = users.map((user, index) => { + return Object.assign({}, user, { id: index }); + }); ``` #### Parse Strings into Numbers @@ -275,14 +275,14 @@ See [our current .eslintrc](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/ 1. `parseInt()` is preferable over `Number()` or `+` ```javascript - // bad - +'10' // 10 + // bad + +'10' // 10 - // good - Number('10') // 10 + // good + Number('10') // 10 - // better - parseInt('10', 10); + // better + parseInt('10', 10); ``` #### CSS classes used for JavaScript @@ -290,15 +290,15 @@ See [our current .eslintrc](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/ 1. If the class is being used in Javascript it needs to be prepend with `js-` ```html - // bad - <button class="add-user"> - Add User - </button> + // bad + <button class="add-user"> + Add User + </button> - // good - <button class="js-add-user"> - Add User - </button> + // good + <button class="js-add-user"> + Add User + </button> ``` ### Vue.js @@ -315,41 +315,41 @@ Please check this [rules][eslint-plugin-vue-rules] for more documentation. 1. Use a function in the bundle file to instantiate the Vue component: ```javascript - // bad - class { - init() { - new Component({}) - } + // bad + class { + init() { + new Component({}) } + } - // good - document.addEventListener('DOMContentLoaded', () => new Vue({ - el: '#element', - components: { - componentName - }, - render: createElement => createElement('component-name'), - })); + // good + document.addEventListener('DOMContentLoaded', () => new Vue({ + el: '#element', + components: { + componentName + }, + render: createElement => createElement('component-name'), + })); ``` 1. Do not use a singleton for the service or the store ```javascript - // bad - class Store { - constructor() { - if (!this.prototype.singleton) { - // do something - } + // bad + class Store { + constructor() { + if (!this.prototype.singleton) { + // do something } } + } - // good - class Store { - constructor() { - // do something - } + // good + class Store { + constructor() { + // do something } + } ``` 1. Use `.vue` for Vue templates. Do not use `%template` in HAML. @@ -360,36 +360,36 @@ Please check this [rules][eslint-plugin-vue-rules] for more documentation. 1. **Reference Naming**: Use PascalCase for their instances: ```javascript - // bad - import cardBoard from 'cardBoard.vue' + // bad + import cardBoard from 'cardBoard.vue' - components: { - cardBoard, - }; + components: { + cardBoard, + }; - // good - import CardBoard from 'cardBoard.vue' + // good + import CardBoard from 'cardBoard.vue' - components: { - CardBoard, - }; + components: { + CardBoard, + }; ``` 1. **Props Naming:** Avoid using DOM component prop names. 1. **Props Naming:** Use kebab-case instead of camelCase to provide props in templates. ```javascript - // bad - <component class="btn"> + // bad + <component class="btn"> - // good - <component css-class="btn"> + // good + <component css-class="btn"> - // bad - <component myProp="prop" /> + // bad + <component myProp="prop" /> - // good - <component my-prop="prop" /> + // good + <component my-prop="prop" /> ``` [#34371]: https://gitlab.com/gitlab-org/gitlab-ce/issues/34371 @@ -401,37 +401,37 @@ Please check this [rules][eslint-plugin-vue-rules] for more documentation. 1. With more than one attribute, all attributes should be on a new line: ```javascript - // bad - <component v-if="bar" - param="baz" /> + // bad + <component v-if="bar" + param="baz" /> - <button class="btn">Click me</button> + <button class="btn">Click me</button> - // good - <component - v-if="bar" - param="baz" - /> + // good + <component + v-if="bar" + param="baz" + /> - <button class="btn"> - Click me - </button> + <button class="btn"> + Click me + </button> ``` 1. The tag can be inline if there is only one attribute: ```javascript - // good - <component bar="bar" /> + // good + <component bar="bar" /> - // good - <component - bar="bar" - /> + // good + <component + bar="bar" + /> - // bad - <component - bar="bar" /> + // bad + <component + bar="bar" /> ``` #### Quotes @@ -439,15 +439,15 @@ Please check this [rules][eslint-plugin-vue-rules] for more documentation. 1. Always use double quotes `"` inside templates and single quotes `'` for all other JS. ```javascript - // bad - template: ` - <button :class='style'>Button</button> - ` + // bad + template: ` + <button :class='style'>Button</button> + ` - // good - template: ` - <button :class="style">Button</button> - ` + // good + template: ` + <button :class="style">Button</button> + ` ``` #### Props @@ -455,37 +455,37 @@ Please check this [rules][eslint-plugin-vue-rules] for more documentation. 1. Props should be declared as an object ```javascript - // bad - props: ['foo'] - - // good - props: { - foo: { - type: String, - required: false, - default: 'bar' - } + // bad + props: ['foo'] + + // good + props: { + foo: { + type: String, + required: false, + default: 'bar' } + } ``` 1. Required key should always be provided when declaring a prop ```javascript - // bad - props: { - foo: { - type: String, - } + // bad + props: { + foo: { + type: String, } + } - // good - props: { - foo: { - type: String, - required: false, - default: 'bar' - } + // good + props: { + foo: { + type: String, + required: false, + default: 'bar' } + } ``` 1. Default key should be provided if the prop is not required. @@ -493,30 +493,30 @@ Please check this [rules][eslint-plugin-vue-rules] for more documentation. On those a default key should not be provided. ```javascript - // good - props: { - foo: { - type: String, - required: false, - } + // good + props: { + foo: { + type: String, + required: false, } + } - // good - props: { - foo: { - type: String, - required: false, - default: 'bar' - } + // good + props: { + foo: { + type: String, + required: false, + default: 'bar' } + } - // good - props: { - foo: { - type: String, - required: true - } + // good + props: { + foo: { + type: String, + required: true } + } ``` #### Data @@ -524,17 +524,17 @@ Please check this [rules][eslint-plugin-vue-rules] for more documentation. 1. `data` method should always be a function ```javascript - // bad - data: { - foo: 'foo' - } + // bad + data: { + foo: 'foo' + } - // good - data() { - return { - foo: 'foo' - }; - } + // good + data() { + return { + foo: 'foo' + }; + } ``` #### Directives @@ -542,31 +542,31 @@ Please check this [rules][eslint-plugin-vue-rules] for more documentation. 1. Shorthand `@` is preferable over `v-on` ```javascript - // bad - <component v-on:click="eventHandler"/> + // bad + <component v-on:click="eventHandler"/> - // good - <component @click="eventHandler"/> + // good + <component @click="eventHandler"/> ``` 1. Shorthand `:` is preferable over `v-bind` ```javascript - // bad - <component v-bind:class="btn"/> + // bad + <component v-bind:class="btn"/> - // good - <component :class="btn"/> + // good + <component :class="btn"/> ``` 1. Shorthand `#` is preferable over `v-slot` ```javascript - // bad - <template v-slot:header></template> + // bad + <template v-slot:header></template> - // good - <template #header></template> + // good + <template #header></template> ``` #### Closing tags @@ -574,11 +574,11 @@ Please check this [rules][eslint-plugin-vue-rules] for more documentation. 1. Prefer self closing component tags ```javascript - // bad - <component></component> + // bad + <component></component> - // good - <component /> + // good + <component /> ``` #### Ordering @@ -610,48 +610,48 @@ When using `v-for` you need to provide a *unique* `:key` attribute for each item 1. If the elements of the array being iterated have an unique `id` it is advised to use it: ```html - <div - v-for="item in items" - :key="item.id" - > - <!-- content --> - </div> + <div + v-for="item in items" + :key="item.id" + > + <!-- content --> + </div> ``` 1. When the elements being iterated don't have a unique id, you can use the array index as the `:key` attribute ```html - <div - v-for="(item, index) in items" - :key="index" - > - <!-- content --> - </div> + <div + v-for="(item, index) in items" + :key="index" + > + <!-- content --> + </div> ``` 1. When using `v-for` with `template` and there is more than one child element, the `:key` values must be unique. It's advised to use `kebab-case` namespaces. ```html - <template v-for="(item, index) in items"> - <span :key="`span-${index}`"></span> - <button :key="`button-${index}`"></button> - </template> + <template v-for="(item, index) in items"> + <span :key="`span-${index}`"></span> + <button :key="`button-${index}`"></button> + </template> ``` 1. When dealing with nested `v-for` use the same guidelines as above. ```html - <div - v-for="item in items" - :key="item.id" + <div + v-for="item in items" + :key="item.id" + > + <span + v-for="element in array" + :key="element.id" > - <span - v-for="element in array" - :key="element.id" - > - <!-- content --> - </span> - </div> + <!-- content --> + </span> + </div> ``` Useful links: @@ -664,19 +664,19 @@ Useful links: 1. Tooltips: Do not rely on `has-tooltip` class name for Vue components ```javascript - // bad - <span - class="has-tooltip" - title="Some tooltip text"> - Text - </span> + // bad + <span + class="has-tooltip" + title="Some tooltip text"> + Text + </span> - // good - <span - v-tooltip - title="Some tooltip text"> - Text - </span> + // good + <span + v-tooltip + title="Some tooltip text"> + Text + </span> ``` 1. Tooltips: When using a tooltip, include the tooltip directive, `./app/assets/javascripts/vue_shared/directives/tooltip.js` @@ -684,13 +684,13 @@ Useful links: 1. Don't change `data-original-title`. ```javascript - // bad - <span data-original-title="tooltip text">Foo</span> + // bad + <span data-original-title="tooltip text">Foo</span> - // good - <span title="tooltip text">Foo</span> + // good + <span title="tooltip text">Foo</span> - $('span').tooltip('_fixTitle'); + $('span').tooltip('_fixTitle'); ``` ### The Javascript/Vue Accord diff --git a/doc/development/fe_guide/vuex.md b/doc/development/fe_guide/vuex.md index 9eeaee4482f..557d3132d71 100644 --- a/doc/development/fe_guide/vuex.md +++ b/doc/development/fe_guide/vuex.md @@ -313,7 +313,7 @@ export default { 1. Do not call a mutation directly. Always use an action to commit a mutation. Doing so will keep consistency throughout the application. From Vuex docs: - > why don't we just call store.commit('action') directly? Well, remember that mutations must be synchronous? Actions aren't. We can perform asynchronous operations inside an action. + > Why don't we just call store.commit('action') directly? Well, remember that mutations must be synchronous? Actions aren't. We can perform asynchronous operations inside an action. ```javascript // component.vue diff --git a/doc/development/interacting_components.md b/doc/development/interacting_components.md index 74d52d808e2..5e6dc8d460a 100644 --- a/doc/development/interacting_components.md +++ b/doc/development/interacting_components.md @@ -9,8 +9,8 @@ when making _backend_ changes that might involve multiple features or [component ## Uploads -GitLab supports uploads to [object storage]. That means every feature and -change that affects uploads should also be tested against [object storage], +GitLab supports uploads to [object storage]. That means every feature and +change that affects uploads should also be tested against [object storage], which is _not_ enabled by default in [GDK](https://gitlab.com/gitlab-org/gitlab-development-kit). When working on a related feature, make sure to enable and test it diff --git a/doc/development/new_fe_guide/development/testing.md b/doc/development/new_fe_guide/development/testing.md index f7ea496d935..e0d413b748b 100644 --- a/doc/development/new_fe_guide/development/testing.md +++ b/doc/development/new_fe_guide/development/testing.md @@ -1,361 +1,6 @@ -# Overview of Frontend Testing +--- +redirect_to: '../../testing_guide/frontend_testing.md' +--- -Tests relevant for frontend development can be found at the following places: +This document was moved to [another location](../../testing_guide/frontend_testing.md). -- `spec/javascripts/` which are run by Karma (command: `yarn karma`) and contain - - [frontend unit tests](#frontend-unit-tests) - - [frontend component tests](#frontend-component-tests) - - [frontend integration tests](#frontend-integration-tests) -- `spec/frontend/` which are run by Jest (command: `yarn jest`) and contain - - [frontend unit tests](#frontend-unit-tests) - - [frontend component tests](#frontend-component-tests) - - [frontend integration tests](#frontend-integration-tests) -- `spec/features/` which are run by RSpec and contain - - [feature tests](#feature-tests) - -All tests in `spec/javascripts/` will eventually be migrated to `spec/frontend/` (see also [#52483](https://gitlab.com/gitlab-org/gitlab-ce/issues/52483)). - -In addition there were feature tests in `features/` run by Spinach in the past. -These have been removed from our codebase in May 2018 ([#23036](https://gitlab.com/gitlab-org/gitlab-ce/issues/23036)). - -See also: - -- [Old testing guide](../../testing_guide/frontend_testing.html). -- [Notes on testing Vue components](../../fe_guide/vue.html#testing-vue-components). - -## Frontend unit tests - -Unit tests are on the lowest abstraction level and typically test functionality that is not directly perceivable by a user. - -### When to use unit tests - -<details> - <summary>exported functions and classes</summary> - Anything that is exported can be reused at various places in a way you have no control over. - Therefore it is necessary to document the expected behavior of the public interface with tests. -</details> - -<details> - <summary>Vuex actions</summary> - Any Vuex action needs to work in a consistent way independent of the component it is triggered from. -</details> - -<details> - <summary>Vuex mutations</summary> - For complex Vuex mutations it helps to identify the source of a problem by separating the tests from other parts of the Vuex store. -</details> - -### When *not* to use unit tests - -<details> - <summary>non-exported functions or classes</summary> - Anything that is not exported from a module can be considered private or an implementation detail and doesn't need to be tested. -</details> - -<details> - <summary>constants</summary> - Testing the value of a constant would mean to copy it. - This results in extra effort without additional confidence that the value is correct. -</details> - -<details> - <summary>Vue components</summary> - Computed properties, methods, and lifecycle hooks can be considered an implementation detail of components and don't need to be tested. - They are implicitly covered by component tests. - The <a href="https://vue-test-utils.vuejs.org/guides/#getting-started">official Vue guidelines</a> suggest the same. -</details> - -### What to mock in unit tests - -<details> - <summary>state of the class under test</summary> - Modifying the state of the class under test directly rather than using methods of the class avoids side-effects in test setup. -</details> - -<details> - <summary>other exported classes</summary> - Every class needs to be tested in isolation to prevent test scenarios from growing exponentially. -</details> - -<details> - <summary>single DOM elements if passed as parameters</summary> - For tests that only operate on single DOM elements rather than a whole page, creating these elements is cheaper than loading a whole HTML fixture. -</details> - -<details> - <summary>all server requests</summary> - When running frontend unit tests, the backend may not be reachable. - Therefore all outgoing requests need to be mocked. -</details> - -<details> - <summary>asynchronous background operations</summary> - Background operations cannot be stopped or waited on, so they will continue running in the following tests and cause side effects. -</details> - -### What *not* to mock in unit tests - -<details> - <summary>non-exported functions or classes</summary> - Everything that is not exported can be considered private to the module and will be implicitly tested via the exported classes / functions. -</details> - -<details> - <summary>methods of the class under test</summary> - By mocking methods of the class under test, the mocks will be tested and not the real methods. -</details> - -<details> - <summary>utility functions (pure functions, or those that only modify parameters)</summary> - If a function has no side effects because it has no state, it is safe to not mock it in tests. -</details> - -<details> - <summary>full HTML pages</summary> - Loading the HTML of a full page slows down tests, so it should be avoided in unit tests. -</details> - -## Frontend component tests - -Component tests cover the state of a single component that is perceivable by a user depending on external signals such as user input, events fired from other components, or application state. - -### When to use component tests - -- Vue components - -### When *not* to use component tests - -<details> - <summary>Vue applications</summary> - Vue applications may contain many components. - Testing them on a component level requires too much effort. - Therefore they are tested on frontend integration level. -</details> - -<details> - <summary>HAML templates</summary> - HAML templates contain only Markup and no frontend-side logic. - Therefore they are not complete components. -</details> - -### What to mock in component tests - -<details> - <summary>DOM</summary> - Operating on the real DOM is significantly slower than on the virtual DOM. -</details> - -<details> - <summary>properties and state of the component under test</summary> - Similarly to testing classes, modifying the properties directly (rather than relying on methods of the component) avoids side-effects. -</details> - -<details> - <summary>Vuex store</summary> - To avoid side effects and keep component tests simple, Vuex stores are replaced with mocks. -</details> - -<details> - <summary>all server requests</summary> - Similar to unit tests, when running component tests, the backend may not be reachable. - Therefore all outgoing requests need to be mocked. -</details> - -<details> - <summary>asynchronous background operations</summary> - Similar to unit tests, background operations cannot be stopped or waited on, so they will continue running in the following tests and cause side effects. -</details> - -<details> - <summary>child components</summary> - Every component is tested individually, so child components are mocked. - See also <a href="https://vue-test-utils.vuejs.org/api/#shallowmount">shallowMount()</a> -</details> - -### What *not* to mock in component tests - -<details> - <summary>methods or computed properties of the component under test</summary> - By mocking part of the component under test, the mocks will be tested and not the real component. -</details> - -<details> - <summary>functions and classes independent from Vue</summary> - All plain JavaScript code is already covered by unit tests and needs not to be mocked in component tests. -</details> - -## Frontend integration tests - -Integration tests cover the interaction between all components on a single page. -Their abstraction level is comparable to how a user would interact with the UI. - -### When to use integration tests - -<details> - <summary>page bundles (<code>index.js</code> files in <code>app/assets/javascripts/pages/</code>)</summary> - Testing the page bundles ensures the corresponding frontend components integrate well. -</details> - -<details> - <summary>Vue applications outside of page bundles</summary> - Testing Vue applications as a whole ensures the corresponding frontend components integrate well. -</details> - -### What to mock in integration tests - -<details> - <summary>HAML views (use fixtures instead)</summary> - Rendering HAML views requires a Rails environment including a running database which we cannot rely on in frontend tests. -</details> - -<details> - <summary>all server requests</summary> - Similar to unit and component tests, when running component tests, the backend may not be reachable. - Therefore all outgoing requests need to be mocked. -</details> - -<details> - <summary>asynchronous background operations that are not perceivable on the page</summary> - Background operations that affect the page need to be tested on this level. - All other background operations cannot be stopped or waited on, so they will continue running in the following tests and cause side effects. -</details> - -### What *not* to mock in integration tests - -<details> - <summary>DOM</summary> - Testing on the real DOM ensures our components work in the environment they are meant for. - Part of this will be delegated to <a href="https://gitlab.com/gitlab-org/quality/team-tasks/issues/45">cross-browser testing</a>. -</details> - -<details> - <summary>properties or state of components</summary> - On this level, all tests can only perform actions a user would do. - For example to change the state of a component, a click event would be fired. -</details> - -<details> - <summary>Vuex stores</summary> - When testing the frontend code of a page as a whole, the interaction between Vue components and Vuex stores is covered as well. -</details> - -## Feature tests - -In contrast to [frontend integration tests](#frontend-integration-tests), feature tests make requests against the real backend instead of using fixtures. -This also implies that database queries are executed which makes this category significantly slower. - -See also the [RSpec testing guidelines](../../testing_guide/best_practices.md#rspec). - -### When to use feature tests - -- use cases that require a backend and cannot be tested using fixtures -- behavior that is not part of a page bundle but defined globally - -### Relevant notes - -A `:js` flag is added to the test to make sure the full environment is loaded. - -``` -scenario 'successfully', :js do - sign_in(create(:admin)) -end -``` - -The steps of each test are written using capybara methods ([documentation](https://www.rubydoc.info/gems/capybara)). - -Bear in mind <abbr title="XMLHttpRequest">XHR</abbr> calls might require you to use `wait_for_requests` in between steps, like so: - -```rspec -find('.form-control').native.send_keys(:enter) - -wait_for_requests - -expect(page).not_to have_selector('.card') -``` - -## Test helpers - -### Vuex Helper: `testAction` - -We have a helper available to make testing actions easier, as per [official documentation](https://vuex.vuejs.org/guide/testing.html): - -``` -testAction( - actions.actionName, // action - { }, // params to be passed to action - state, // state - [ - { type: types.MUTATION}, - { type: types.MUTATION_1, payload: {}}, - ], // mutations committed - [ - { type: 'actionName', payload: {}}, - { type: 'actionName1', payload: {}}, - ] // actions dispatched - done, -); -``` - -Check an example in [spec/javascripts/ide/stores/actions_spec.jsspec/javascripts/ide/stores/actions_spec.js](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/spec/javascripts/ide/stores/actions_spec.js). - -### Vue Helper: `mountComponent` - -To make mounting a Vue component easier and more readable, we have a few helpers available in `spec/helpers/vue_mount_component_helper`. - -- `createComponentWithStore` -- `mountComponentWithStore` - -Examples of usage: - -``` -beforeEach(() => { - vm = createComponentWithStore(Component, store); - - vm.$store.state.currentBranchId = 'master'; - - vm.$mount(); -}, -``` - -``` -beforeEach(() => { - vm = mountComponentWithStore(Component, { - el: '#dummy-element', - store, - props: { badge }, - }); -}, -``` - -Don't forget to clean up: - -``` -afterEach(() => { - vm.$destroy(); -}); -``` - -## Testing with older browsers - -Some regressions only affect a specific browser version. We can install and test in particular browsers with either Firefox or Browserstack using the following steps: - -### Browserstack - -[Browserstack](https://www.browserstack.com/) allows you to test more than 1200 mobile devices and browsers. -You can use it directly through the [live app](https://www.browserstack.com/live) or you can install the [chrome extension](https://chrome.google.com/webstore/detail/browserstack/nkihdmlheodkdfojglpcjjmioefjahjb) for easy access. -You can find the credentials on 1Password, under `frontendteam@gitlab.com`. - -### Firefox - -#### macOS - -You can download any older version of Firefox from the releases FTP server, <https://ftp.mozilla.org/pub/firefox/releases/> - -1. From the website, select a version, in this case `50.0.1`. -1. Go to the mac folder. -1. Select your preferred language, you will find the dmg package inside, download it. -1. Drag and drop the application to any other folder but the `Applications` folder. -1. Rename the application to something like `Firefox_Old`. -1. Move the application to the `Applications` folder. -1. Open up a terminal and run `/Applications/Firefox_Old.app/Contents/MacOS/firefox-bin -profilemanager` to create a new profile specific to that Firefox version. -1. Once the profile has been created, quit the app, and run it again like normal. You now have a working older Firefox version. diff --git a/doc/development/new_fe_guide/modules/dirty_submit.md b/doc/development/new_fe_guide/modules/dirty_submit.md index 6c03958b463..217743ea395 100644 --- a/doc/development/new_fe_guide/modules/dirty_submit.md +++ b/doc/development/new_fe_guide/modules/dirty_submit.md @@ -1,7 +1,6 @@ # Dirty Submit -> [Introduced][ce-21115] in GitLab 11.3. -> [dirty_submit][dirty-submit] +> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/21115) in GitLab 11.3. ## Summary @@ -9,6 +8,9 @@ Prevent submitting forms with no changes. Currently handles `input`, `textarea` and `select` elements. +Also, see [the code](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/app/assets/javascripts/dirty_submit/) +within the GitLab project. + ## Usage ```js @@ -18,6 +20,3 @@ new DirtySubmitForm(document.querySelector('form')); // or new DirtySubmitForm(document.querySelectorAll('form')); ``` - -[ce-21115]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/21115 -[dirty-submit]: https://gitlab.com/gitlab-org/gitlab-ce/blob/master/app/assets/javascripts/dirty_submit/
\ No newline at end of file diff --git a/doc/development/new_fe_guide/style/javascript.md b/doc/development/new_fe_guide/style/javascript.md index 802ebd12d92..b742d567f41 100644 --- a/doc/development/new_fe_guide/style/javascript.md +++ b/doc/development/new_fe_guide/style/javascript.md @@ -192,4 +192,4 @@ rules only if you are invoking/instantiating existing code modules. - [class-method-use-this](http://eslint.org/docs/rules/class-methods-use-this) > Note: Disable these rules on a per line basis. This makes it easier to refactor - in the future. E.g. use `eslint-disable-next-line` or `eslint-disable-line`. +> in the future. E.g. use `eslint-disable-next-line` or `eslint-disable-line`. diff --git a/doc/development/query_recorder.md b/doc/development/query_recorder.md index a6b60149ea4..3787e2ef187 100644 --- a/doc/development/query_recorder.md +++ b/doc/development/query_recorder.md @@ -36,6 +36,13 @@ it "avoids N+1 database queries" do end ``` +## Use request specs instead of controller specs + +Use a [request spec](https://gitlab.com/gitlab-org/gitlab-ce/tree/master/spec/requests) when writing a N+1 test on the controller level. + +Controller specs should not be used to write N+1 tests as the controller is only initialized once per example. +This could lead to false successes where subsequent "requests" could have queries reduced (e.g. because of memoization). + ## Finding the source of the query It may be useful to identify the source of the queries by looking at the call backtrace. diff --git a/doc/development/shell_scripting_guide/index.md b/doc/development/shell_scripting_guide/index.md index ae7f2154682..0809f8b1a0a 100644 --- a/doc/development/shell_scripting_guide/index.md +++ b/doc/development/shell_scripting_guide/index.md @@ -24,7 +24,8 @@ Having said all of the above, we recommend staying away from shell scripts as much as possible. A language like Ruby or Python (if required for consistency with codebases that we leverage) is almost always a better choice. The high-level interpreted languages have more readable syntax, offer much more -mature capabilities for unit-testing, linting, and error reporting. +mature capabilities for unit-testing, linting, and error reporting. + Use shell scripts only if there's a strong restriction on project's dependencies size or any other requirements that are more important in a particular case. @@ -48,12 +49,12 @@ that is: This section describes the tools that should be made a mandatory part of a project's CI pipeline if it contains shell scripts. These tools -automate shell code formatting, checking for errors or vulnerabilities, etc. +automate shell code formatting, checking for errors or vulnerabilities, etc. ### Linting We're using the [ShellCheck](https://www.shellcheck.net/) utility in its default configuration to lint our -shell scripts. +shell scripts. All projects with shell scripts should use this GitLab CI/CD job: @@ -98,7 +99,7 @@ NOTE: **Note:** This is a work in progress. It is an [ongoing effort](https://gitlab.com/gitlab-org/gitlab-ce/issues/64016) to evaluate different tools for the -automated testing of shell scripts (like [BATS](https://github.com/sstephenson/bats)). +automated testing of shell scripts (like [BATS](https://github.com/sstephenson/bats)). ## Code Review diff --git a/doc/development/testing_guide/frontend_testing.md b/doc/development/testing_guide/frontend_testing.md index 2985278cc92..52ac746716c 100644 --- a/doc/development/testing_guide/frontend_testing.md +++ b/doc/development/testing_guide/frontend_testing.md @@ -593,6 +593,365 @@ end [capybara]: https://github.com/teamcapybara/capybara [jasmine]: https://jasmine.github.io/ +## Overview of Frontend Testing Levels + +Tests relevant for frontend development can be found at the following places: + +- `spec/javascripts/` which are run by Karma (command: `yarn karma`) and contain + - [frontend unit tests](#frontend-unit-tests) + - [frontend component tests](#frontend-component-tests) + - [frontend integration tests](#frontend-integration-tests) +- `spec/frontend/` which are run by Jest (command: `yarn jest`) and contain + - [frontend unit tests](#frontend-unit-tests) + - [frontend component tests](#frontend-component-tests) + - [frontend integration tests](#frontend-integration-tests) +- `spec/features/` which are run by RSpec and contain + - [feature tests](#feature-tests) + +All tests in `spec/javascripts/` will eventually be migrated to `spec/frontend/` (see also [#52483](https://gitlab.com/gitlab-org/gitlab-ce/issues/52483)). + +In addition, there used to be feature tests in `features/`, run by Spinach. +These were removed from the codebase in May 2018 ([#23036](https://gitlab.com/gitlab-org/gitlab-ce/issues/23036)). + +See also [Notes on testing Vue components](../fe_guide/vue.html#testing-vue-components). + +### Frontend unit tests + +Unit tests are on the lowest abstraction level and typically test functionality that is not directly perceivable by a user. + +#### When to use unit tests + +<details> + <summary>exported functions and classes</summary> + Anything that is exported can be reused at various places in a way you have no control over. + Therefore it is necessary to document the expected behavior of the public interface with tests. +</details> + +<details> + <summary>Vuex actions</summary> + Any Vuex action needs to work in a consistent way independent of the component it is triggered from. +</details> + +<details> + <summary>Vuex mutations</summary> + For complex Vuex mutations it helps to identify the source of a problem by separating the tests from other parts of the Vuex store. +</details> + +#### When *not* to use unit tests + +<details> + <summary>non-exported functions or classes</summary> + Anything that is not exported from a module can be considered private or an implementation detail and doesn't need to be tested. +</details> + +<details> + <summary>constants</summary> + Testing the value of a constant would mean to copy it. + This results in extra effort without additional confidence that the value is correct. +</details> + +<details> + <summary>Vue components</summary> + Computed properties, methods, and lifecycle hooks can be considered an implementation detail of components and don't need to be tested. + They are implicitly covered by component tests. + The <a href="https://vue-test-utils.vuejs.org/guides/#getting-started">official Vue guidelines</a> suggest the same. +</details> + +#### What to mock in unit tests + +<details> + <summary>state of the class under test</summary> + Modifying the state of the class under test directly rather than using methods of the class avoids side-effects in test setup. +</details> + +<details> + <summary>other exported classes</summary> + Every class needs to be tested in isolation to prevent test scenarios from growing exponentially. +</details> + +<details> + <summary>single DOM elements if passed as parameters</summary> + For tests that only operate on single DOM elements rather than a whole page, creating these elements is cheaper than loading a whole HTML fixture. +</details> + +<details> + <summary>all server requests</summary> + When running frontend unit tests, the backend may not be reachable. + Therefore all outgoing requests need to be mocked. +</details> + +<details> + <summary>asynchronous background operations</summary> + Background operations cannot be stopped or waited on, so they will continue running in the following tests and cause side effects. +</details> + +#### What *not* to mock in unit tests + +<details> + <summary>non-exported functions or classes</summary> + Everything that is not exported can be considered private to the module and will be implicitly tested via the exported classes / functions. +</details> + +<details> + <summary>methods of the class under test</summary> + By mocking methods of the class under test, the mocks will be tested and not the real methods. +</details> + +<details> + <summary>utility functions (pure functions, or those that only modify parameters)</summary> + If a function has no side effects because it has no state, it is safe to not mock it in tests. +</details> + +<details> + <summary>full HTML pages</summary> + Loading the HTML of a full page slows down tests, so it should be avoided in unit tests. +</details> + +### Frontend component tests + +Component tests cover the state of a single component that is perceivable by a user depending on external signals such as user input, events fired from other components, or application state. + +#### When to use component tests + +- Vue components + +#### When *not* to use component tests + +<details> + <summary>Vue applications</summary> + Vue applications may contain many components. + Testing them on a component level requires too much effort. + Therefore they are tested on frontend integration level. +</details> + +<details> + <summary>HAML templates</summary> + HAML templates contain only Markup and no frontend-side logic. + Therefore they are not complete components. +</details> + +#### What to mock in component tests + +<details> + <summary>DOM</summary> + Operating on the real DOM is significantly slower than on the virtual DOM. +</details> + +<details> + <summary>properties and state of the component under test</summary> + Similarly to testing classes, modifying the properties directly (rather than relying on methods of the component) avoids side-effects. +</details> + +<details> + <summary>Vuex store</summary> + To avoid side effects and keep component tests simple, Vuex stores are replaced with mocks. +</details> + +<details> + <summary>all server requests</summary> + Similar to unit tests, when running component tests, the backend may not be reachable. + Therefore all outgoing requests need to be mocked. +</details> + +<details> + <summary>asynchronous background operations</summary> + Similar to unit tests, background operations cannot be stopped or waited on, so they will continue running in the following tests and cause side effects. +</details> + +<details> + <summary>child components</summary> + Every component is tested individually, so child components are mocked. + See also <a href="https://vue-test-utils.vuejs.org/api/#shallowmount">shallowMount()</a> +</details> + +#### What *not* to mock in component tests + +<details> + <summary>methods or computed properties of the component under test</summary> + By mocking part of the component under test, the mocks will be tested and not the real component. +</details> + +<details> + <summary>functions and classes independent from Vue</summary> + All plain JavaScript code is already covered by unit tests and needs not to be mocked in component tests. +</details> + +### Frontend integration tests + +Integration tests cover the interaction between all components on a single page. +Their abstraction level is comparable to how a user would interact with the UI. + +#### When to use integration tests + +<details> + <summary>page bundles (<code>index.js</code> files in <code>app/assets/javascripts/pages/</code>)</summary> + Testing the page bundles ensures the corresponding frontend components integrate well. +</details> + +<details> + <summary>Vue applications outside of page bundles</summary> + Testing Vue applications as a whole ensures the corresponding frontend components integrate well. +</details> + +#### What to mock in integration tests + +<details> + <summary>HAML views (use fixtures instead)</summary> + Rendering HAML views requires a Rails environment including a running database which we cannot rely on in frontend tests. +</details> + +<details> + <summary>all server requests</summary> + Similar to unit and component tests, when running component tests, the backend may not be reachable. + Therefore all outgoing requests need to be mocked. +</details> + +<details> + <summary>asynchronous background operations that are not perceivable on the page</summary> + Background operations that affect the page need to be tested on this level. + All other background operations cannot be stopped or waited on, so they will continue running in the following tests and cause side effects. +</details> + +#### What *not* to mock in integration tests + +<details> + <summary>DOM</summary> + Testing on the real DOM ensures our components work in the environment they are meant for. + Part of this will be delegated to <a href="https://gitlab.com/gitlab-org/quality/team-tasks/issues/45">cross-browser testing</a>. +</details> + +<details> + <summary>properties or state of components</summary> + On this level, all tests can only perform actions a user would do. + For example to change the state of a component, a click event would be fired. +</details> + +<details> + <summary>Vuex stores</summary> + When testing the frontend code of a page as a whole, the interaction between Vue components and Vuex stores is covered as well. +</details> + +### Feature tests + +In contrast to [frontend integration tests](#frontend-integration-tests), feature tests make requests against the real backend instead of using fixtures. +This also implies that database queries are executed which makes this category significantly slower. + +See also the [RSpec testing guidelines](../testing_guide/best_practices.md#rspec). + +#### When to use feature tests + +- Use cases that require a backend and cannot be tested using fixtures. +- Behavior that is not part of a page bundle but defined globally. + +#### Relevant notes + +A `:js` flag is added to the test to make sure the full environment is loaded. + +```js +scenario 'successfully', :js do + sign_in(create(:admin)) +end +``` + +The steps of each test are written using capybara methods ([documentation](https://www.rubydoc.info/gems/capybara)). + +Bear in mind <abbr title="XMLHttpRequest">XHR</abbr> calls might require you to use `wait_for_requests` in between steps, like so: + +```rspec +find('.form-control').native.send_keys(:enter) + +wait_for_requests + +expect(page).not_to have_selector('.card') +``` + +## Test helpers + +### Vuex Helper: `testAction` + +We have a helper available to make testing actions easier, as per [official documentation](https://vuex.vuejs.org/guide/testing.html): + +```js +testAction( + actions.actionName, // action + { }, // params to be passed to action + state, // state + [ + { type: types.MUTATION}, + { type: types.MUTATION_1, payload: {}}, + ], // mutations committed + [ + { type: 'actionName', payload: {}}, + { type: 'actionName1', payload: {}}, + ] // actions dispatched + done, +); +``` + +Check an example in [spec/javascripts/ide/stores/actions_spec.jsspec/javascripts/ide/stores/actions_spec.js](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/spec/javascripts/ide/stores/actions_spec.js). + +### Vue Helper: `mountComponent` + +To make mounting a Vue component easier and more readable, we have a few helpers available in `spec/helpers/vue_mount_component_helper`: + +- `createComponentWithStore` +- `mountComponentWithStore` + +Examples of usage: + +```js +beforeEach(() => { + vm = createComponentWithStore(Component, store); + + vm.$store.state.currentBranchId = 'master'; + + vm.$mount(); +}); +``` + +```js +beforeEach(() => { + vm = mountComponentWithStore(Component, { + el: '#dummy-element', + store, + props: { badge }, + }); +}); +``` + +Don't forget to clean up: + +```js +afterEach(() => { + vm.$destroy(); +}); +``` + +## Testing with older browsers + +Some regressions only affect a specific browser version. We can install and test in particular browsers with either Firefox or Browserstack using the following steps: + +### Browserstack + +[Browserstack](https://www.browserstack.com/) allows you to test more than 1200 mobile devices and browsers. +You can use it directly through the [live app](https://www.browserstack.com/live) or you can install the [chrome extension](https://chrome.google.com/webstore/detail/browserstack/nkihdmlheodkdfojglpcjjmioefjahjb) for easy access. +You can find the credentials on 1Password, under `frontendteam@gitlab.com`. + +### Firefox + +#### macOS + +You can download any older version of Firefox from the releases FTP server, <https://ftp.mozilla.org/pub/firefox/releases/>: + +1. From the website, select a version, in this case `50.0.1`. +1. Go to the mac folder. +1. Select your preferred language, you will find the dmg package inside, download it. +1. Drag and drop the application to any other folder but the `Applications` folder. +1. Rename the application to something like `Firefox_Old`. +1. Move the application to the `Applications` folder. +1. Open up a terminal and run `/Applications/Firefox_Old.app/Contents/MacOS/firefox-bin -profilemanager` to create a new profile specific to that Firefox version. +1. Once the profile has been created, quit the app, and run it again like normal. You now have a working older Firefox version. + --- [Return to Testing documentation](index.md) diff --git a/doc/development/testing_guide/review_apps.md b/doc/development/testing_guide/review_apps.md index 7843fc4c874..11449712a04 100644 --- a/doc/development/testing_guide/review_apps.md +++ b/doc/development/testing_guide/review_apps.md @@ -255,8 +255,8 @@ that a machine will hit the "too many mount points" problem in the future. thousands of unused Docker images.** > We have to start somewhere and improve later. Also, we're using the - CNG-mirror project to store these Docker images so that we can just wipe out - the registry at some point, and use a new fresh, empty one. + > CNG-mirror project to store these Docker images so that we can just wipe out + > the registry at some point, and use a new fresh, empty one. **How do we secure this from abuse? Apps are open to the world so we need to find a way to limit it to only us.** diff --git a/doc/development/testing_guide/testing_levels.md b/doc/development/testing_guide/testing_levels.md index 6c3a3171d39..0090c84cbf0 100644 --- a/doc/development/testing_guide/testing_levels.md +++ b/doc/development/testing_guide/testing_levels.md @@ -63,7 +63,7 @@ They're useful to test permissions, redirections, what view is rendered etc. | Code path | Tests path | Testing engine | Notes | | --------- | ---------- | -------------- | ----- | -| `app/controllers/` | `spec/controllers/` | RSpec | | +| `app/controllers/` | `spec/controllers/` | RSpec | For N+1 tests, use [request specs](../query_recorder.md#use-request-specs-instead-of-controller-specs) | | `app/mailers/` | `spec/mailers/` | RSpec | | | `lib/api/` | `spec/requests/api/` | RSpec | | | `app/assets/javascripts/` | `spec/javascripts/`, `spec/frontend/` | Karma & Jest | More details in the [Frontend Testing guide](frontend_testing.md) section. | diff --git a/doc/topics/autodevops/index.md b/doc/topics/autodevops/index.md index 9c1258fa1aa..4bfcd4aad96 100644 --- a/doc/topics/autodevops/index.md +++ b/doc/topics/autodevops/index.md @@ -584,6 +584,52 @@ Unless you have a `Dockerfile` in your repo, your image is built with Herokuish, and you must prefix commands run in these images with `/bin/herokuish procfile exec` to replicate the environment where your application will run. +#### Workers + +Some web applications need to run extra deployments for "worker processes". For +example it is common in a Rails application to have a separate worker process +to run background tasks like sending emails. + +The [default Helm chart](https://gitlab.com/gitlab-org/charts/auto-deploy-app) +used in Auto Deploy [has support for running worker +processes](https://gitlab.com/gitlab-org/charts/auto-deploy-app/merge_requests/9). + +In order to run a worker you'll need to ensure that it is able to respond to +the standard health checks which expect a successful HTTP response on port +`5000`. For sidekiq you could make use of the +[sidekiq_alive gem](https://rubygems.org/gems/sidekiq_alive) to do this. + +In order to work with sidekiq you'll also need to ensure your deployments have +access to a redis instance. Auto DevOps won't deploy this for you so you'll +need to manage this separately and then set a CI variable +`K8S_SECRET_REDIS_URL` which the URL of this instance to ensure it's passed +into your deployments. + +Once you have configured your worker to respond to health checks you you will +need to configure a CI variable `HELM_UPGRADE_EXTRA_ARGS` with the value +`--values helm-values.yaml`. Then you can, for example, run a +[sidekiq](https://github.com/mperham/sidekiq) worker for your rails application +by adding a file named `helm-values.yaml` to your repo with the following +content: + +```yml +workers: + sidekiq: + replicaCount: 1 + command: + - /bin/herokuish + - procfile + - exec + - sidekiq + preStopCommand: + - /bin/herokuish + - procfile + - exec + - sidekiqctl + - quiet + terminationGracePeriodSeconds: 60 +``` + ### Auto Monitoring See the [requirements](#requirements) for Auto Monitoring to enable this stage. diff --git a/doc/user/project/import/gitlab_com.md b/doc/user/project/import/gitlab_com.md index f48a158e2d3..2f87f257754 100644 --- a/doc/user/project/import/gitlab_com.md +++ b/doc/user/project/import/gitlab_com.md @@ -1,21 +1,21 @@ # Project importing from GitLab.com to your private GitLab instance -You can import your existing GitLab.com projects to your GitLab instance. But keep in mind that it is possible only if -GitLab.com integration is enabled on your GitLab instance. +You can import your existing GitLab.com projects to your GitLab instance, but keep in +mind that it is possible only if GitLab.com integration is enabled on your GitLab instance. [Read more about GitLab.com integration for self-managed GitLab instances](../../../integration/gitlab.md). To get to the importer page you need to go to "New project" page. >**Note:** -If you are interested in importing Wiki and Merge Request data to your new -instance, you'll need to follow the instructions for [project export](../settings/import_export.md) +If you are interested in importing Wiki and Merge Request data to your new instance, +you'll need to follow the instructions for [exporting a project](../settings/import_export.md#exporting-a-project-and-its-data) -![New project page](img/gitlab_new_project_page.png) +![New project page](img/gitlab_new_project_page_v12_2.png) -Click on the "Import projects from GitLab.com" link and you will be redirected to GitLab.com +Go to the **Import Projects** tab, then click on **GitLab.com**, and you will be redirected to GitLab.com for permission to access your projects. After accepting, you'll be automatically redirected to the importer. ![Importer page](img/gitlab_importer.png) -To import a project, you can simple click "Import". The importer will import your repository and issues. +To import a project, click "Import". The importer will import your repository and issues. Once the importer is done, a new GitLab project will be created with your imported data. diff --git a/doc/user/project/import/img/gitlab_new_project_page.png b/doc/user/project/import/img/gitlab_new_project_page.png Binary files differdeleted file mode 100644 index c673724f436..00000000000 --- a/doc/user/project/import/img/gitlab_new_project_page.png +++ /dev/null diff --git a/doc/user/project/import/img/gitlab_new_project_page_v12_2.png b/doc/user/project/import/img/gitlab_new_project_page_v12_2.png Binary files differnew file mode 100644 index 00000000000..e79c27f32c0 --- /dev/null +++ b/doc/user/project/import/img/gitlab_new_project_page_v12_2.png diff --git a/doc/user/project/merge_requests/img/incrementally_expand_merge_request_diffs_v12_2.png b/doc/user/project/merge_requests/img/incrementally_expand_merge_request_diffs_v12_2.png Binary files differnew file mode 100644 index 00000000000..ee94dbdea5c --- /dev/null +++ b/doc/user/project/merge_requests/img/incrementally_expand_merge_request_diffs_v12_2.png diff --git a/doc/user/project/merge_requests/index.md b/doc/user/project/merge_requests/index.md index 8a82b163481..2794cbc0f39 100644 --- a/doc/user/project/merge_requests/index.md +++ b/doc/user/project/merge_requests/index.md @@ -497,6 +497,15 @@ list. ![Merge request diff file navigation](img/merge_request_diff_file_navigation.png) +### Incrementally expand merge request diffs + +By default, the diff shows only the parts of a file which are changed. +To view more unchanged lines above or below a change click on the +**Expand up** or **Expand down** icons. You can also click on **Show all lines** +to expand the entire file. + +![Incrementally expand merge request diffs](img/incrementally_expand_merge_request_diffs_v12_2.png) + ## Ignore whitespace changes in Merge Request diff view If you click the **Hide whitespace changes** button, you can see the diff diff --git a/doc/user/project/repository/img/repository_languages.png b/doc/user/project/repository/img/repository_languages.png Binary files differdeleted file mode 100644 index 5977ad7faae..00000000000 --- a/doc/user/project/repository/img/repository_languages.png +++ /dev/null diff --git a/doc/user/project/repository/img/repository_languages_v12_2.gif b/doc/user/project/repository/img/repository_languages_v12_2.gif Binary files differnew file mode 100644 index 00000000000..d0a0e57c919 --- /dev/null +++ b/doc/user/project/repository/img/repository_languages_v12_2.gif diff --git a/doc/user/project/repository/index.md b/doc/user/project/repository/index.md index 84d63d29929..bd966185c94 100644 --- a/doc/user/project/repository/index.md +++ b/doc/user/project/repository/index.md @@ -182,7 +182,7 @@ were used and display this on the projects pages. If this information is missing be added after updating the default branch on the project. This process can take up to 5 minutes. -![Repository Languages bar](img/repository_languages.png) +![Repository Languages bar](img/repository_languages_v12_2.gif) Not all files are detected, among others; documentation, vendored code, and most markup languages are excluded. This behaviour can be diff --git a/doc/workflow/lfs/lfs_administration.md b/doc/workflow/lfs/lfs_administration.md index 3160b0c4deb..7e880b3009d 100644 --- a/doc/workflow/lfs/lfs_administration.md +++ b/doc/workflow/lfs/lfs_administration.md @@ -46,8 +46,7 @@ In `config/gitlab.yml`: ## Storing LFS objects in remote object storage -> [Introduced][ee-2760] in [GitLab Premium][eep] 10.0. Brought to GitLab Core -in 10.7. +> [Introduced][ee-2760] in [GitLab Premium][eep] 10.0. Brought to GitLab Core in 10.7. It is possible to store LFS objects in remote object storage which allows you to offload local hard disk R/W operations, and free up disk space significantly. @@ -91,7 +90,7 @@ Here is a configuration example with S3. | `aws_access_key_id` | AWS credentials, or compatible | `ABC123DEF456` | | `aws_secret_access_key` | AWS credentials, or compatible | `ABC123DEF456ABC123DEF456ABC123DEF456` | | `aws_signature_version` | AWS signature version to use. 2 or 4 are valid options. Digital Ocean Spaces and other providers may need 2. | 4 | -| `enable_signature_v4_streaming` | Set to true to enable HTTP chunked transfers with AWS v4 signatures (https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-streaming.html). Oracle Cloud S3 needs this to be false | true +| `enable_signature_v4_streaming` | Set to true to enable HTTP chunked transfers with [AWS v4 signatures](https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-streaming.html). Oracle Cloud S3 needs this to be false | true | | `region` | AWS region | us-east-1 | | `host` | S3 compatible host for when not using AWS, e.g. `localhost` or `storage.example.com` | s3.amazonaws.com | | `endpoint` | Can be used when configuring an S3 compatible service such as [Minio](https://www.minio.io), by entering a URL such as `http://127.0.0.1:9000` | (optional) | @@ -107,7 +106,9 @@ Here is a configuration example with GCS. | `google_client_email` | The email address of the service account | `foo@gcp-project-12345.iam.gserviceaccount.com` | | `google_json_key_location` | The json key path | `/path/to/gcp-project-12345-abcde.json` | -_NOTE: The service account must have permission to access the bucket. [See more](https://cloud.google.com/storage/docs/authentication)_ +NOTE: **Note:** +The service account must have permission to access the bucket. +[See more](https://cloud.google.com/storage/docs/authentication) Here is a configuration example with Rackspace Cloud Files. @@ -119,7 +120,13 @@ Here is a configuration example with Rackspace Cloud Files. | `rackspace_region` | The Rackspace storage region to use, a three letter code from the [list of service access endpoints](https://developer.rackspace.com/docs/cloud-files/v1/general-api-info/service-access/) | `iad` | | `rackspace_temp_url_key` | The private key you have set in the Rackspace API for temporary URLs. Read more [here](https://developer.rackspace.com/docs/cloud-files/v1/use-cases/public-access-to-your-cloud-files-account/#tempurl) | `ABC123DEF456ABC123DEF456ABC123DE` | -_NOTES: Regardless of whether the container has public access enabled or disabled, Fog will use the TempURL method to grant access to LFS objects. If you see errors in logs referencing instantiating storage with a temp-url-key, ensure that you have set they key properly on the Rackspace API and in gitlab.rb. You can verify the value of the key Rackspace has set by sending a GET request with token header to the service access endpoint URL and comparing the output of the returned headers._ +NOTE: **Note:** +Regardless of whether the container has public access enabled or disabled, Fog will +use the TempURL method to grant access to LFS objects. If you see errors in logs referencing +instantiating storage with a temp-url-key, ensure that you have set they key properly +on the Rackspace API and in gitlab.rb. You can verify the value of the key Rackspace +has set by sending a GET request with token header to the service access endpoint URL +and comparing the output of the returned headers. ### Manual uploading to an object storage @@ -167,13 +174,13 @@ On Omnibus installations, the settings are prefixed by `lfs_object_store_`: 1. Save the file and [reconfigure GitLab]s for the changes to take effect. 1. Migrate any existing local LFS objects to the object storage: - ```bash - gitlab-rake gitlab:lfs:migrate - ``` + ```bash + gitlab-rake gitlab:lfs:migrate + ``` - This will migrate existing LFS objects to object storage. New LFS objects - will be forwarded to object storage unless - `gitlab_rails['lfs_object_store_background_upload']` is set to false. + This will migrate existing LFS objects to object storage. New LFS objects + will be forwarded to object storage unless + `gitlab_rails['lfs_object_store_background_upload']` is set to false. ### S3 for installations from source @@ -203,13 +210,13 @@ For source installations the settings are nested under `lfs:` and then 1. Save the file and [restart GitLab][] for the changes to take effect. 1. Migrate any existing local LFS objects to the object storage: - ```bash - sudo -u git -H bundle exec rake gitlab:lfs:migrate RAILS_ENV=production - ``` + ```bash + sudo -u git -H bundle exec rake gitlab:lfs:migrate RAILS_ENV=production + ``` - This will migrate existing LFS objects to object storage. New LFS objects - will be forwarded to object storage unless `background_upload` is set to - false. + This will migrate existing LFS objects to object storage. New LFS objects + will be forwarded to object storage unless `background_upload` is set to + false. ## Storage statistics diff --git a/doc/workflow/lfs/manage_large_binaries_with_git_lfs.md b/doc/workflow/lfs/manage_large_binaries_with_git_lfs.md index 264372a512d..f5593927cc2 100644 --- a/doc/workflow/lfs/manage_large_binaries_with_git_lfs.md +++ b/doc/workflow/lfs/manage_large_binaries_with_git_lfs.md @@ -35,9 +35,10 @@ Documentation for GitLab instance administrators is under [LFS administration do - Git LFS always assumes HTTPS so if you have GitLab server on HTTP you will have to add the URL to Git config manually (see [troubleshooting](#troubleshooting)) ->**Note**: With 8.12 GitLab added LFS support to SSH. The Git LFS communication - still goes over HTTP, but now the SSH client passes the correct credentials - to the Git LFS client, so no action is required by the user. +NOTE: **Note:** +With 8.12 GitLab added LFS support to SSH. The Git LFS communication +still goes over HTTP, but now the SSH client passes the correct credentials +to the Git LFS client, so no action is required by the user. ## Using Git LFS @@ -61,12 +62,13 @@ git commit -am "Added Debian iso" # commit the file meta data git push origin master # sync the git repo and large file to the GitLab server ``` -> **Note**: Make sure that `.gitattributes` is tracked by git. Otherwise Git -> LFS will not be working properly for people cloning the project. -> -> ```bash -> git add .gitattributes -> ``` +NOTE: **Note:** +**Make sure** that `.gitattributes` is tracked by Git. Otherwise Git +LFS will not be working properly for people cloning the project. + +```bash +git add .gitattributes +``` Cloning the repository works the same as before. Git automatically detects the LFS-tracked files and clones them via HTTP. If you performed the git clone @@ -216,9 +218,10 @@ git config --add lfs.url "http://gitlab.example.com/group/project.git/info/lfs" ### Credentials are always required when pushing an object ->**Note**: With 8.12 GitLab added LFS support to SSH. The Git LFS communication - still goes over HTTP, but now the SSH client passes the correct credentials - to the Git LFS client, so no action is required by the user. +NOTE: **Note:** +With 8.12 GitLab added LFS support to SSH. The Git LFS communication +still goes over HTTP, but now the SSH client passes the correct credentials +to the Git LFS client, so no action is required by the user. Given that Git LFS uses HTTP Basic Authentication to authenticate the user pushing the LFS object on every push for every object, user HTTPS credentials are required. diff --git a/doc/workflow/lfs/migrate_from_git_annex_to_git_lfs.md b/doc/workflow/lfs/migrate_from_git_annex_to_git_lfs.md index 75673d23799..5ceeb3253f1 100644 --- a/doc/workflow/lfs/migrate_from_git_annex_to_git_lfs.md +++ b/doc/workflow/lfs/migrate_from_git_annex_to_git_lfs.md @@ -76,7 +76,7 @@ Here you'll find a guide on Since Annex files are stored as objects with symlinks and cannot be directly modified, we need to first remove those symlinks. ->**Note:** +NOTE: **Note:** Make sure the you read about the [`direct` mode][annex-direct] as it contains useful information that may fit in your use case. Note that `annex direct` is deprecated in Git Annex version 6, so you may need to upgrade your repository diff --git a/doc/workflow/repository_mirroring.md b/doc/workflow/repository_mirroring.md index 0b8e7d851b0..753518d0424 100644 --- a/doc/workflow/repository_mirroring.md +++ b/doc/workflow/repository_mirroring.md @@ -37,8 +37,7 @@ The following are some possible use cases for repository mirroring: ## Pushing to a remote repository **(CORE)** -> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/249) in GitLab Enterprise -> Edition 8.7. [Moved to GitLab Core](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/18715) in 10.8. +> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/249) in GitLab Enterprise Edition 8.7. [Moved to GitLab Core](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/18715) in 10.8. For an existing project, you can set up push mirroring as follows: @@ -67,8 +66,7 @@ section. ### Push only protected branches **(CORE)** -> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/3350) in -> [GitLab Starter](https://about.gitlab.com/pricing/) 10.3. [Moved to GitLab Core](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/18715) in 10.8. +> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/3350) in [GitLab Starter](https://about.gitlab.com/pricing/) 10.3. [Moved to GitLab Core](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/18715) in 10.8. You can choose to only push your protected branches from GitLab to your remote repository. @@ -98,8 +96,7 @@ The repository will push soon. To force a push, click the appropriate button. ## Pulling from a remote repository **(STARTER)** -> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/51) in GitLab Enterprise Edition 8.2. -> [Added Git LFS support](https://gitlab.com/gitlab-org/gitlab-ee/issues/10871) in [GitLab Starter](https://about.gitlab.com/pricing/) 11.11. +> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/51) in GitLab Enterprise Edition 8.2. [Added Git LFS support](https://gitlab.com/gitlab-org/gitlab-ee/issues/10871) in [GitLab Starter](https://about.gitlab.com/pricing/) 11.11. NOTE: **Note:** This feature [is available for free](https://gitlab.com/gitlab-org/gitlab-ee/issues/10361) to GitLab.com users until September 22nd, 2019. @@ -157,8 +154,7 @@ Repository mirrors are updated as Sidekiq becomes available to process them. If ### SSH authentication -> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/2551) for Pull mirroring in [GitLab Starter](https://about.gitlab.com/pricing/) 9.5. -> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/22982) for Push mirroring in [GitLab Core](https://about.gitlab.com/pricing/) 11.6 +> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/2551) for Pull mirroring in [GitLab Starter](https://about.gitlab.com/pricing/) 9.5. [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/22982) for Push mirroring in [GitLab Core](https://about.gitlab.com/pricing/) 11.6 SSH authentication is mutual: @@ -245,8 +241,7 @@ key to keep the mirror running. ### Overwrite diverged branches **(STARTER)** -> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/4559) in -> [GitLab Starter](https://about.gitlab.com/pricing/) 10.6. +> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/4559) in [GitLab Starter](https://about.gitlab.com/pricing/) 10.6. You can choose to always update your local branches with remote versions, even if they have diverged from the remote. @@ -258,8 +253,7 @@ To use this option, check the **Overwrite diverged branches** box when creating ### Only mirror protected branches **(STARTER)** -> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/3326) in -> [GitLab Starter](https://about.gitlab.com/pricing/) 10.3. +> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/3326) in [GitLab Starter](https://about.gitlab.com/pricing/) 10.3. You can choose to pull mirror only the protected branches from your remote repository to GitLab. Non-protected branches are not mirrored and can diverge. @@ -268,8 +262,7 @@ To use this option, check the **Only mirror protected branches** box when creati ### Hard failure **(STARTER)** -> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/3117) in -> [GitLab Starter](https://about.gitlab.com/pricing/) 10.2. +> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/3117) in [GitLab Starter](https://about.gitlab.com/pricing/) 10.2. Once the mirroring process is unsuccessfully retried 14 times in a row, it will get marked as hard failed. This will become visible in either the: @@ -282,8 +275,7 @@ project mirroring again by [Forcing an update](#forcing-an-update-core). ### Trigger update using API **(STARTER)** -> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/3453) in -[GitLab Starter](https://about.gitlab.com/pricing/) 10.3. +> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/3453) in [GitLab Starter](https://about.gitlab.com/pricing/) 10.3. Pull mirroring uses polling to detect new branches and commits added upstream, often minutes afterwards. If you notify GitLab by [API](../api/projects.md#start-the-pull-mirroring-process-for-a-project-starter), @@ -325,9 +317,10 @@ protected branches. ### Preventing conflicts using a `pre-receive` hook -> **Warning:** The solution proposed will negatively impact the performance of -> Git push operations because they will be proxied to the upstream Git -> repository. +CAUTION: **Warning:** +The solution proposed will negatively impact the performance of +Git push operations because they will be proxied to the upstream Git +repository. A server-side `pre-receive` hook can be used to prevent the race condition described above by only accepting the push after first pushing the commit to diff --git a/doc/workflow/todos.md b/doc/workflow/todos.md index 0432c406f31..211d242e2d3 100644 --- a/doc/workflow/todos.md +++ b/doc/workflow/todos.md @@ -35,8 +35,8 @@ A To Do displays on your To-Do List when: - You are `@mentioned` in a comment on a commit - A job in the CI pipeline running for your merge request failed, but this job is not allowed to fail -- An open merge request becomes unmergeable due to conflict, and you are either: - - The author +- An open merge request becomes unmergeable due to conflict, and you are either: + - The author - Have set it to automatically merge once the pipeline succeeds To-do triggers are not affected by [GitLab Notification Email settings](notifications.md). diff --git a/lib/api/api.rb b/lib/api/api.rb index e500a93b31e..219ed45eff6 100644 --- a/lib/api/api.rb +++ b/lib/api/api.rb @@ -18,7 +18,7 @@ module API formatter: Gitlab::GrapeLogging::Formatters::LogrageWithTimestamp.new, include: [ GrapeLogging::Loggers::FilterParameters.new(LOG_FILTERS), - GrapeLogging::Loggers::ClientEnv.new, + Gitlab::GrapeLogging::Loggers::ClientEnvLogger.new, Gitlab::GrapeLogging::Loggers::RouteLogger.new, Gitlab::GrapeLogging::Loggers::UserLogger.new, Gitlab::GrapeLogging::Loggers::QueueDurationLogger.new, diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 09253ab6b0e..5e66b4e76a5 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -645,7 +645,10 @@ module API end end - expose :subscribed do |issue, options| + # Calculating the value of subscribed field triggers Markdown + # processing. We can't do that for multiple issues / merge + # requests in a single API request. + expose :subscribed, if: -> (_, options) { options.fetch(:include_subscribed, true) } do |issue, options| issue.subscribed?(options[:current_user], options[:project] || issue.project) end end diff --git a/lib/api/issues.rb b/lib/api/issues.rb index d687acf3423..7819c2de515 100644 --- a/lib/api/issues.rb +++ b/lib/api/issues.rb @@ -96,7 +96,8 @@ module API with: Entities::Issue, with_labels_details: declared_params[:with_labels_details], current_user: current_user, - issuable_metadata: issuable_meta_data(issues, 'Issue', current_user) + issuable_metadata: issuable_meta_data(issues, 'Issue', current_user), + include_subscribed: false } present issues, options @@ -122,7 +123,8 @@ module API with: Entities::Issue, with_labels_details: declared_params[:with_labels_details], current_user: current_user, - issuable_metadata: issuable_meta_data(issues, 'Issue', current_user) + issuable_metadata: issuable_meta_data(issues, 'Issue', current_user), + include_subscribed: false } present issues, options diff --git a/lib/gitlab/action_rate_limiter.rb b/lib/gitlab/action_rate_limiter.rb index fdb06d00548..0e8707af631 100644 --- a/lib/gitlab/action_rate_limiter.rb +++ b/lib/gitlab/action_rate_limiter.rb @@ -49,9 +49,9 @@ module Gitlab request_information = { message: 'Action_Rate_Limiter_Request', env: type, - ip: request.ip, + remote_ip: request.ip, request_method: request.request_method, - fullpath: request.fullpath + path: request.fullpath } if current_user diff --git a/lib/gitlab/ci/build/policy/variables.rb b/lib/gitlab/ci/build/policy/variables.rb index 0698136166a..e9c8864123f 100644 --- a/lib/gitlab/ci/build/policy/variables.rb +++ b/lib/gitlab/ci/build/policy/variables.rb @@ -10,7 +10,7 @@ module Gitlab end def satisfied_by?(pipeline, seed) - variables = seed.to_resource.scoped_variables_hash + variables = seed.scoped_variables_hash statements = @expressions.map do |statement| ::Gitlab::Ci::Pipeline::Expression::Statement diff --git a/lib/gitlab/ci/build/rules.rb b/lib/gitlab/ci/build/rules.rb new file mode 100644 index 00000000000..89623a809c9 --- /dev/null +++ b/lib/gitlab/ci/build/rules.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +module Gitlab + module Ci + module Build + class Rules + include ::Gitlab::Utils::StrongMemoize + + Result = Struct.new(:when, :start_in) + + def initialize(rule_hashes, default_when = 'on_success') + @rule_list = Rule.fabricate_list(rule_hashes) + @default_when = default_when + end + + def evaluate(pipeline, build) + if @rule_list.nil? + Result.new(@default_when) + elsif matched_rule = match_rule(pipeline, build) + Result.new( + matched_rule.attributes[:when] || @default_when, + matched_rule.attributes[:start_in] + ) + else + Result.new('never') + end + end + + private + + def match_rule(pipeline, build) + @rule_list.find { |rule| rule.matches?(pipeline, build) } + end + end + end + end +end diff --git a/lib/gitlab/ci/build/rules/rule.rb b/lib/gitlab/ci/build/rules/rule.rb new file mode 100644 index 00000000000..8d52158c8d2 --- /dev/null +++ b/lib/gitlab/ci/build/rules/rule.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +module Gitlab + module Ci + module Build + class Rules::Rule + attr_accessor :attributes + + def self.fabricate_list(list) + list.map(&method(:new)) if list + end + + def initialize(spec) + @clauses = [] + @attributes = {} + + spec.each do |type, value| + if clause = Clause.fabricate(type, value) + @clauses << clause + else + @attributes.merge!(type => value) + end + end + end + + def matches?(pipeline, build) + @clauses.all? { |clause| clause.satisfied_by?(pipeline, build) } + end + end + end + end +end diff --git a/lib/gitlab/ci/build/rules/rule/clause.rb b/lib/gitlab/ci/build/rules/rule/clause.rb new file mode 100644 index 00000000000..ff0baf3348c --- /dev/null +++ b/lib/gitlab/ci/build/rules/rule/clause.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +module Gitlab + module Ci + module Build + class Rules::Rule::Clause + ## + # Abstract class that defines an interface of a single + # job rule specification. + # + # Used for job's inclusion rules configuration. + # + UnknownClauseError = Class.new(StandardError) + + def self.fabricate(type, value) + type = type.to_s.camelize + + self.const_get(type).new(value) if self.const_defined?(type) + end + + def initialize(spec) + @spec = spec + end + + def satisfied_by?(pipeline, seed = nil) + raise NotImplementedError + end + end + end + end +end diff --git a/lib/gitlab/ci/build/rules/rule/clause/changes.rb b/lib/gitlab/ci/build/rules/rule/clause/changes.rb new file mode 100644 index 00000000000..81d2ee6c24c --- /dev/null +++ b/lib/gitlab/ci/build/rules/rule/clause/changes.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +module Gitlab + module Ci + module Build + class Rules::Rule::Clause::Changes < Rules::Rule::Clause + def initialize(globs) + @globs = Array(globs) + end + + def satisfied_by?(pipeline, seed) + return true if pipeline.modified_paths.nil? + + pipeline.modified_paths.any? do |path| + @globs.any? do |glob| + File.fnmatch?(glob, path, File::FNM_PATHNAME | File::FNM_DOTMATCH | File::FNM_EXTGLOB) + end + end + end + end + end + end +end diff --git a/lib/gitlab/ci/build/rules/rule/clause/if.rb b/lib/gitlab/ci/build/rules/rule/clause/if.rb new file mode 100644 index 00000000000..18c3b450f95 --- /dev/null +++ b/lib/gitlab/ci/build/rules/rule/clause/if.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +module Gitlab + module Ci + module Build + class Rules::Rule::Clause::If < Rules::Rule::Clause + def initialize(expression) + @expression = expression + end + + def satisfied_by?(pipeline, seed) + variables = seed.scoped_variables_hash + + ::Gitlab::Ci::Pipeline::Expression::Statement.new(@expression, variables).truthful? + end + end + end + end +end diff --git a/lib/gitlab/ci/config/entry/job.rb b/lib/gitlab/ci/config/entry/job.rb index 29a52b9da17..6e11c582750 100644 --- a/lib/gitlab/ci/config/entry/job.rb +++ b/lib/gitlab/ci/config/entry/job.rb @@ -11,7 +11,8 @@ module Gitlab include ::Gitlab::Config::Entry::Configurable include ::Gitlab::Config::Entry::Attributable - ALLOWED_KEYS = %i[tags script only except type image services + ALLOWED_WHEN = %w[on_success on_failure always manual delayed].freeze + ALLOWED_KEYS = %i[tags script only except rules type image services allow_failure type stage when start_in artifacts cache dependencies needs before_script after_script variables environment coverage retry parallel extends].freeze @@ -19,12 +20,19 @@ module Gitlab REQUIRED_BY_NEEDS = %i[stage].freeze validations do + validates :config, type: Hash validates :config, allowed_keys: ALLOWED_KEYS validates :config, required_keys: REQUIRED_BY_NEEDS, if: :has_needs? validates :config, presence: true validates :script, presence: true validates :name, presence: true validates :name, type: Symbol + validates :config, + disallowed_keys: { + in: %i[only except when start_in], + message: 'key may not be used with `rules`' + }, + if: :has_rules? with_options allow_nil: true do validates :tags, array_of_strings: true @@ -32,17 +40,19 @@ module Gitlab validates :parallel, numericality: { only_integer: true, greater_than_or_equal_to: 2, less_than_or_equal_to: 50 } - validates :when, - inclusion: { in: %w[on_success on_failure always manual delayed], - message: 'should be on_success, on_failure, ' \ - 'always, manual or delayed' } + validates :when, inclusion: { + in: ALLOWED_WHEN, + message: "should be one of: #{ALLOWED_WHEN.join(', ')}" + } + validates :dependencies, array_of_strings: true validates :needs, array_of_strings: true validates :extends, array_of_strings_or_string: true + validates :rules, array_of_hashes: true end validates :start_in, duration: { limit: '1 day' }, if: :delayed? - validates :start_in, absence: true, unless: :delayed? + validates :start_in, absence: true, if: -> { has_rules? || !delayed? } validate do next unless dependencies.present? @@ -91,6 +101,9 @@ module Gitlab entry :except, Entry::Policy, description: 'Refs policy this job will be executed for.' + entry :rules, Entry::Rules, + description: 'List of evaluable Rules to determine job inclusion.' + entry :variables, Entry::Variables, description: 'Environment variables available for this job.' @@ -112,7 +125,7 @@ module Gitlab :parallel, :needs attributes :script, :tags, :allow_failure, :when, :dependencies, - :needs, :retry, :parallel, :extends, :start_in + :needs, :retry, :parallel, :extends, :start_in, :rules def self.matching?(name, config) !name.to_s.start_with?('.') && @@ -151,6 +164,10 @@ module Gitlab self.when == 'delayed' end + def has_rules? + @config.try(:key?, :rules) + end + def ignored? allow_failure.nil? ? manual_action? : allow_failure end diff --git a/lib/gitlab/ci/config/entry/rules.rb b/lib/gitlab/ci/config/entry/rules.rb new file mode 100644 index 00000000000..65cad0880f5 --- /dev/null +++ b/lib/gitlab/ci/config/entry/rules.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +module Gitlab + module Ci + class Config + module Entry + class Rules < ::Gitlab::Config::Entry::Node + include ::Gitlab::Config::Entry::Validatable + + validations do + validates :config, presence: true + validates :config, type: Array + end + + def compose!(deps = nil) + super(deps) do + @config.each_with_index do |rule, index| + @entries[index] = ::Gitlab::Config::Entry::Factory.new(Entry::Rules::Rule) + .value(rule) + .with(key: "rule", parent: self, description: "rule definition.") # rubocop:disable CodeReuse/ActiveRecord + .create! + end + + @entries.each_value do |entry| + entry.compose!(deps) + end + end + end + end + end + end + end +end diff --git a/lib/gitlab/ci/config/entry/rules/rule.rb b/lib/gitlab/ci/config/entry/rules/rule.rb new file mode 100644 index 00000000000..1f2a34ec90e --- /dev/null +++ b/lib/gitlab/ci/config/entry/rules/rule.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +module Gitlab + module Ci + class Config + module Entry + class Rules::Rule < ::Gitlab::Config::Entry::Node + include ::Gitlab::Config::Entry::Validatable + include ::Gitlab::Config::Entry::Attributable + + CLAUSES = %i[if changes].freeze + ALLOWED_KEYS = %i[if changes when start_in].freeze + ALLOWED_WHEN = %w[on_success on_failure always never manual delayed].freeze + + attributes :if, :changes, :when, :start_in + + validations do + validates :config, presence: true + validates :config, type: { with: Hash } + validates :config, allowed_keys: ALLOWED_KEYS + validates :config, disallowed_keys: %i[start_in], unless: :specifies_delay? + validates :start_in, presence: true, if: :specifies_delay? + validates :start_in, duration: { limit: '1 day' }, if: :specifies_delay? + + with_options allow_nil: true do + validates :if, expression: true + validates :changes, array_of_strings: true + validates :when, allowed_values: { in: ALLOWED_WHEN } + end + end + + def specifies_delay? + self.when == 'delayed' + end + + def default + end + end + end + end + end +end diff --git a/lib/gitlab/ci/pipeline/seed/build.rb b/lib/gitlab/ci/pipeline/seed/build.rb index 7ec03d132c0..1066331062b 100644 --- a/lib/gitlab/ci/pipeline/seed/build.rb +++ b/lib/gitlab/ci/pipeline/seed/build.rb @@ -7,7 +7,7 @@ module Gitlab class Build < Seed::Base include Gitlab::Utils::StrongMemoize - delegate :dig, to: :@attributes + delegate :dig, to: :@seed_attributes # When the `ci_dag_limit_needs` is enabled it uses the lower limit LOW_NEEDS_LIMIT = 5 @@ -15,14 +15,20 @@ module Gitlab def initialize(pipeline, attributes, previous_stages) @pipeline = pipeline - @attributes = attributes + @seed_attributes = attributes @previous_stages = previous_stages @needs_attributes = dig(:needs_attributes) + @using_rules = attributes.key?(:rules) + @using_only = attributes.key?(:only) + @using_except = attributes.key?(:except) + @only = Gitlab::Ci::Build::Policy .fabricate(attributes.delete(:only)) @except = Gitlab::Ci::Build::Policy .fabricate(attributes.delete(:except)) + @rules = Gitlab::Ci::Build::Rules + .new(attributes.delete(:rules)) end def name @@ -31,8 +37,13 @@ module Gitlab def included? strong_memoize(:inclusion) do - all_of_only? && - none_of_except? + if @using_rules + included_by_rules? + elsif @using_only || @using_except + all_of_only? && none_of_except? + else + true + end end end @@ -45,19 +56,13 @@ module Gitlab end def attributes - @attributes.merge( - pipeline: @pipeline, - project: @pipeline.project, - user: @pipeline.user, - ref: @pipeline.ref, - tag: @pipeline.tag, - trigger_request: @pipeline.legacy_trigger, - protected: @pipeline.protected_ref? - ) + @seed_attributes + .deep_merge(pipeline_attributes) + .deep_merge(rules_attributes) end def bridge? - attributes_hash = @attributes.to_h + attributes_hash = @seed_attributes.to_h attributes_hash.dig(:options, :trigger).present? || (attributes_hash.dig(:options, :bridge_needs).instance_of?(Hash) && attributes_hash.dig(:options, :bridge_needs, :pipeline).present?) @@ -73,6 +78,18 @@ module Gitlab end end + def scoped_variables_hash + strong_memoize(:scoped_variables_hash) do + # This is a temporary piece of technical debt to allow us access + # to the CI variables to evaluate rules before we persist a Build + # with the result. We should refactor away the extra Build.new, + # but be able to get CI Variables directly from the Seed::Build. + ::Ci::Build.new( + @seed_attributes.merge(pipeline_attributes) + ).scoped_variables_hash + end + end + private def all_of_only? @@ -109,6 +126,28 @@ module Gitlab HARD_NEEDS_LIMIT end end + + def pipeline_attributes + { + pipeline: @pipeline, + project: @pipeline.project, + user: @pipeline.user, + ref: @pipeline.ref, + tag: @pipeline.tag, + trigger_request: @pipeline.legacy_trigger, + protected: @pipeline.protected_ref? + } + end + + def included_by_rules? + rules_attributes[:when] != 'never' + end + + def rules_attributes + strong_memoize(:rules_attributes) do + @using_rules ? @rules.evaluate(@pipeline, self).to_h.compact : {} + end + end end end end diff --git a/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml b/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml index 4190de73e1f..90278122361 100644 --- a/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml +++ b/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml @@ -46,11 +46,14 @@ sast: SAST_DOCKER_CLIENT_NEGOTIATION_TIMEOUT \ SAST_PULL_ANALYZER_IMAGE_TIMEOUT \ SAST_RUN_ANALYZER_TIMEOUT \ + SAST_JAVA_VERSION \ ANT_HOME \ ANT_PATH \ GRADLE_PATH \ JAVA_OPTS \ JAVA_PATH \ + JAVA_8_VERSION \ + JAVA_11_VERSION \ MAVEN_CLI_OPTS \ MAVEN_PATH \ MAVEN_REPO_PATH \ diff --git a/lib/gitlab/config/entry/validators.rb b/lib/gitlab/config/entry/validators.rb index 0289e675c6b..374f929878e 100644 --- a/lib/gitlab/config/entry/validators.rb +++ b/lib/gitlab/config/entry/validators.rb @@ -20,8 +20,10 @@ module Gitlab present_keys = value.try(:keys).to_a & options[:in] if present_keys.any? - record.errors.add(attribute, "contains disallowed keys: " + - present_keys.join(', ')) + message = options[:message] || "contains disallowed keys" + message += ": #{present_keys.join(', ')}" + + record.errors.add(attribute, message) end end end @@ -65,6 +67,16 @@ module Gitlab end end + class ArrayOfHashesValidator < ActiveModel::EachValidator + include LegacyValidationHelpers + + def validate_each(record, attribute, value) + unless value.is_a?(Array) && value.map { |hsh| hsh.is_a?(Hash) }.all? + record.errors.add(attribute, 'should be an array of hashes') + end + end + end + class ArrayOrStringValidator < ActiveModel::EachValidator def validate_each(record, attribute, value) unless value.is_a?(Array) || value.is_a?(String) @@ -231,6 +243,14 @@ module Gitlab end end + class ExpressionValidator < ActiveModel::EachValidator + def validate_each(record, attribute, value) + unless value.is_a?(String) && ::Gitlab::Ci::Pipeline::Expression::Statement.new(value).valid? + record.errors.add(attribute, 'Invalid expression syntax') + end + end + end + class PortNamePresentAndUniqueValidator < ActiveModel::EachValidator def validate_each(record, attribute, value) return unless value.is_a?(Array) diff --git a/lib/gitlab/grape_logging/loggers/client_env_logger.rb b/lib/gitlab/grape_logging/loggers/client_env_logger.rb new file mode 100644 index 00000000000..3acc6f6a2ef --- /dev/null +++ b/lib/gitlab/grape_logging/loggers/client_env_logger.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +# This is a fork of +# https://github.com/aserafin/grape_logging/blob/master/lib/grape_logging/loggers/client_env.rb +# to use remote_ip instead of ip. +module Gitlab + module GrapeLogging + module Loggers + class ClientEnvLogger < ::GrapeLogging::Loggers::Base + def parameters(request, _) + { remote_ip: request.env["HTTP_X_FORWARDED_FOR"] || request.env["REMOTE_ADDR"], ua: request.env["HTTP_USER_AGENT"] } + end + end + end + end +end diff --git a/lib/gitlab/repository_cache_adapter.rb b/lib/gitlab/repository_cache_adapter.rb index e40c366ed02..75503ee1789 100644 --- a/lib/gitlab/repository_cache_adapter.rb +++ b/lib/gitlab/repository_cache_adapter.rb @@ -23,6 +23,37 @@ module Gitlab end end + # Caches and strongly memoizes the method as a Redis Set. + # + # This only works for methods that do not take any arguments. The method + # should return an Array of Strings to be cached. + # + # In addition to overriding the named method, a "name_include?" method is + # defined. This uses the "SISMEMBER" query to efficiently check membership + # without needing to load the entire set into memory. + # + # name - The name of the method to be cached. + # fallback - A value to fall back to if the repository does not exist, or + # in case of a Git error. Defaults to nil. + def cache_method_as_redis_set(name, fallback: nil) + uncached_name = alias_uncached_method(name) + + define_method(name) do + cache_method_output_as_redis_set(name, fallback: fallback) do + __send__(uncached_name) # rubocop:disable GitlabSecurity/PublicSend + end + end + + define_method("#{name}_include?") do |value| + # If the cache isn't populated, we can't rely on it + return redis_set_cache.include?(name, value) if redis_set_cache.exist?(name) + + # Since we have to pull all branch names to populate the cache, use + # the data we already have to answer the query just this once + __send__(name).include?(value) # rubocop:disable GitlabSecurity/PublicSend + end + end + # Caches truthy values from the method. All values are strongly memoized, # and cached in RequestStore. # @@ -84,6 +115,11 @@ module Gitlab raise NotImplementedError end + # RepositorySetCache to be used. Should be overridden by the including class + def redis_set_cache + raise NotImplementedError + end + # List of cached methods. Should be overridden by the including class def cached_methods raise NotImplementedError @@ -100,6 +136,18 @@ module Gitlab end end + # Caches and strongly memoizes the supplied block as a Redis Set. The result + # will be provided as a sorted array. + # + # name - The name of the method to be cached. + # fallback - A value to fall back to if the repository does not exist, or + # in case of a Git error. Defaults to nil. + def cache_method_output_as_redis_set(name, fallback: nil, &block) + memoize_method_output(name, fallback: fallback) do + redis_set_cache.fetch(name, &block).sort + end + end + # Caches truthy values from the supplied block. All values are strongly # memoized, and cached in RequestStore. # @@ -154,6 +202,7 @@ module Gitlab clear_memoization(memoizable_name(name)) end + expire_redis_set_method_caches(methods) expire_request_store_method_caches(methods) end @@ -169,6 +218,10 @@ module Gitlab end end + def expire_redis_set_method_caches(methods) + methods.each { |name| redis_set_cache.expire(name) } + end + # All cached repository methods depend on the existence of a Git repository, # so if the repository doesn't exist, we already know not to call it. def fallback_early?(method_name) diff --git a/lib/gitlab/repository_set_cache.rb b/lib/gitlab/repository_set_cache.rb new file mode 100644 index 00000000000..fb634328a95 --- /dev/null +++ b/lib/gitlab/repository_set_cache.rb @@ -0,0 +1,67 @@ +# frozen_string_literal: true + +# Interface to the Redis-backed cache store for keys that use a Redis set +module Gitlab + class RepositorySetCache + attr_reader :repository, :namespace, :expires_in + + def initialize(repository, extra_namespace: nil, expires_in: 2.weeks) + @repository = repository + @namespace = "#{repository.full_path}:#{repository.project.id}" + @namespace = "#{@namespace}:#{extra_namespace}" if extra_namespace + @expires_in = expires_in + end + + def cache_key(type) + [type, namespace, 'set'].join(':') + end + + def expire(key) + with { |redis| redis.del(cache_key(key)) } + end + + def exist?(key) + with { |redis| redis.exists(cache_key(key)) } + end + + def read(key) + with { |redis| redis.smembers(cache_key(key)) } + end + + def write(key, value) + full_key = cache_key(key) + + with do |redis| + redis.multi do + redis.del(full_key) + + # Splitting into groups of 1000 prevents us from creating a too-long + # Redis command + value.in_groups_of(1000, false) { |subset| redis.sadd(full_key, subset) } + + redis.expire(full_key, expires_in) + end + end + + value + end + + def fetch(key, &block) + if exist?(key) + read(key) + else + write(key, yield) + end + end + + def include?(key, value) + with { |redis| redis.sismember(cache_key(key), value) } + end + + private + + def with(&blk) + Gitlab::Redis::Cache.with(&blk) # rubocop:disable CodeReuse/ActiveRecord + end + end +end diff --git a/lib/gitlab/sentry.rb b/lib/gitlab/sentry.rb index 764db14d720..005cb3112b8 100644 --- a/lib/gitlab/sentry.rb +++ b/lib/gitlab/sentry.rb @@ -39,9 +39,14 @@ module Gitlab # development and test. If you need development and test to behave # just the same as production you can use this instead of # track_exception. + # + # If the exception implements the method `sentry_extra_data` and that method + # returns a Hash, then the return value of that method will be merged into + # `extra`. Exceptions can use this mechanism to provide structured data + # to sentry in addition to their message and back-trace. def self.track_acceptable_exception(exception, issue_url: nil, extra: {}) if enabled? - extra[:issue_url] = issue_url if issue_url + extra = build_extra_data(exception, issue_url, extra) context # Make sure we've set everything we know in the context Raven.capture_exception(exception, tags: default_tags, extra: extra) @@ -58,5 +63,15 @@ module Gitlab locale: I18n.locale } end + + def self.build_extra_data(exception, issue_url, extra) + exception.try(:sentry_extra_data)&.tap do |data| + extra.merge!(data) if data.is_a?(Hash) + end + + extra.merge({ issue_url: issue_url }.compact) + end + + private_class_method :build_extra_data end end diff --git a/lib/gitlab/sidekiq_middleware/metrics.rb b/lib/gitlab/sidekiq_middleware/metrics.rb index b06ffa9c121..3dc9521ee8b 100644 --- a/lib/gitlab/sidekiq_middleware/metrics.rb +++ b/lib/gitlab/sidekiq_middleware/metrics.rb @@ -3,6 +3,10 @@ module Gitlab module SidekiqMiddleware class Metrics + # SIDEKIQ_LATENCY_BUCKETS are latency histogram buckets better suited to Sidekiq + # timeframes than the DEFAULT_BUCKET definition. Defined in seconds. + SIDEKIQ_LATENCY_BUCKETS = [0.1, 0.25, 0.5, 1, 2.5, 5, 10, 60, 300, 600].freeze + def initialize @metrics = init_metrics end @@ -31,7 +35,7 @@ module Gitlab def init_metrics { - sidekiq_jobs_completion_seconds: ::Gitlab::Metrics.histogram(:sidekiq_jobs_completion_seconds, 'Seconds to complete sidekiq job'), + sidekiq_jobs_completion_seconds: ::Gitlab::Metrics.histogram(:sidekiq_jobs_completion_seconds, 'Seconds to complete sidekiq job', buckets: SIDEKIQ_LATENCY_BUCKETS), sidekiq_jobs_failed_total: ::Gitlab::Metrics.counter(:sidekiq_jobs_failed_total, 'Sidekiq jobs failed'), sidekiq_jobs_retried_total: ::Gitlab::Metrics.counter(:sidekiq_jobs_retried_total, 'Sidekiq jobs retried'), sidekiq_running_jobs: ::Gitlab::Metrics.gauge(:sidekiq_running_jobs, 'Number of Sidekiq jobs running', {}, :livesum) diff --git a/lib/gitlab/usage_data_counters/note_counter.rb b/lib/gitlab/usage_data_counters/note_counter.rb index e93a0bcfa27..672450ec82b 100644 --- a/lib/gitlab/usage_data_counters/note_counter.rb +++ b/lib/gitlab/usage_data_counters/note_counter.rb @@ -4,7 +4,7 @@ module Gitlab::UsageDataCounters class NoteCounter < BaseCounter KNOWN_EVENTS = %w[create].freeze PREFIX = 'note' - COUNTABLE_TYPES = %w[Snippet].freeze + COUNTABLE_TYPES = %w[Snippet Commit MergeRequest].freeze class << self def redis_key(event, noteable_type) @@ -24,9 +24,9 @@ module Gitlab::UsageDataCounters end def totals - { - snippet_comment: read(:create, 'Snippet') - } + COUNTABLE_TYPES.map do |countable_type| + [:"#{countable_type.underscore}_comment", read(:create, countable_type)] + end.to_h end private diff --git a/lib/gt_one_coercion.rb b/lib/gt_one_coercion.rb deleted file mode 100644 index 99be51bc8c6..00000000000 --- a/lib/gt_one_coercion.rb +++ /dev/null @@ -1,7 +0,0 @@ -# frozen_string_literal: true - -class GtOneCoercion < Virtus::Attribute - def coerce(value) - [1, value.to_i].max - end -end diff --git a/locale/gitlab.pot b/locale/gitlab.pot index d84203ee911..26e6cb524bd 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -8020,6 +8020,9 @@ msgstr "" msgid "Pipelines for last year" msgstr "" +msgid "Pipelines for merge requests are configured. A detached pipeline runs in the context of the merge request, and not against the merged result. Learn more on the documentation for Pipelines for Merged Results." +msgstr "" + msgid "Pipelines settings for '%{project_name}' were successfully updated." msgstr "" @@ -11160,9 +11163,6 @@ msgstr "" msgid "The character highlighter helps you keep the subject line to %{titleLength} characters and wrap the body at %{bodyLength} so they are readable in git." msgstr "" -msgid "The code of a detached pipeline is tested against the source branch instead of merged results" -msgstr "" - msgid "The coding stage shows the time from the first commit to creating the merge request. The data will automatically be added here once you create your first merge request." msgstr "" diff --git a/package.json b/package.json index 2b9a00d1cbd..97ea872ee61 100644 --- a/package.json +++ b/package.json @@ -30,13 +30,13 @@ "webpack-vrt": "NODE_OPTIONS=\"--max-old-space-size=3584\" NODE_ENV=production webpack --config config/webpack.config.review_toolbar.js" }, "dependencies": { - "@babel/core": "^7.4.4", - "@babel/plugin-proposal-class-properties": "^7.4.4", + "@babel/core": "^7.5.5", + "@babel/plugin-proposal-class-properties": "^7.5.5", "@babel/plugin-proposal-json-strings": "^7.2.0", "@babel/plugin-proposal-private-methods": "^7.4.4", "@babel/plugin-syntax-dynamic-import": "^7.2.0", "@babel/plugin-syntax-import-meta": "^7.2.0", - "@babel/preset-env": "^7.4.4", + "@babel/preset-env": "^7.5.5", "@gitlab/csslab": "^1.9.0", "@gitlab/svgs": "^1.68.0", "@gitlab/ui": "5.15.0", @@ -145,7 +145,7 @@ "xterm": "^3.5.0" }, "devDependencies": { - "@babel/plugin-transform-modules-commonjs": "^7.2.0", + "@babel/plugin-transform-modules-commonjs": "^7.5.0", "@gitlab/eslint-config": "^1.6.0", "@gitlab/eslint-plugin-i18n": "^1.1.0", "@gitlab/eslint-plugin-vue-i18n": "^1.2.0", diff --git a/spec/controllers/groups/group_members_controller_spec.rb b/spec/controllers/groups/group_members_controller_spec.rb index 908c564e761..0c3dd971582 100644 --- a/spec/controllers/groups/group_members_controller_spec.rb +++ b/spec/controllers/groups/group_members_controller_spec.rb @@ -172,7 +172,7 @@ describe Groups::GroupMembersController do it '[JS] removes user from members' do delete :destroy, params: { group_id: group, id: member }, xhr: true - expect(response).to be_success + expect(response).to be_successful expect(group.members).not_to include member end end diff --git a/spec/controllers/groups/milestones_controller_spec.rb b/spec/controllers/groups/milestones_controller_spec.rb index bf164aeed38..41927907fd1 100644 --- a/spec/controllers/groups/milestones_controller_spec.rb +++ b/spec/controllers/groups/milestones_controller_spec.rb @@ -186,7 +186,7 @@ describe Groups::MilestonesController do it "removes milestone" do delete :destroy, params: { group_id: group.to_param, id: milestone.iid }, format: :js - expect(response).to be_success + expect(response).to be_successful expect { Milestone.find(milestone.id) }.to raise_exception(ActiveRecord::RecordNotFound) end end diff --git a/spec/controllers/health_check_controller_spec.rb b/spec/controllers/health_check_controller_spec.rb index 92f005faf4a..b48b7dc86e0 100644 --- a/spec/controllers/health_check_controller_spec.rb +++ b/spec/controllers/health_check_controller_spec.rb @@ -33,14 +33,14 @@ describe HealthCheckController do get :index - expect(response).to be_success + expect(response).to be_successful expect(response.content_type).to eq 'text/plain' end it 'supports passing the token in query params' do get :index, params: { token: token } - expect(response).to be_success + expect(response).to be_successful expect(response.content_type).to eq 'text/plain' end end @@ -54,14 +54,14 @@ describe HealthCheckController do it 'supports successful plaintext response' do get :index - expect(response).to be_success + expect(response).to be_successful expect(response.content_type).to eq 'text/plain' end it 'supports successful json response' do get :index, format: :json - expect(response).to be_success + expect(response).to be_successful expect(response.content_type).to eq 'application/json' expect(json_response['healthy']).to be true end @@ -69,7 +69,7 @@ describe HealthCheckController do it 'supports successful xml response' do get :index, format: :xml - expect(response).to be_success + expect(response).to be_successful expect(response.content_type).to eq 'application/xml' expect(xml_response['healthy']).to be true end @@ -77,7 +77,7 @@ describe HealthCheckController do it 'supports successful responses for specific checks' do get :index, params: { checks: 'email' }, format: :json - expect(response).to be_success + expect(response).to be_successful expect(response.content_type).to eq 'application/json' expect(json_response['healthy']).to be true end diff --git a/spec/controllers/help_controller_spec.rb b/spec/controllers/help_controller_spec.rb index 43c910da7a5..03b6e85b653 100644 --- a/spec/controllers/help_controller_spec.rb +++ b/spec/controllers/help_controller_spec.rb @@ -114,7 +114,7 @@ describe HelpController do path: 'user/project/img/labels_default_v12_1' }, format: :png - expect(response).to be_success + expect(response).to be_successful expect(response.content_type).to eq 'image/png' expect(response.headers['Content-Disposition']).to match(/^inline;/) end diff --git a/spec/controllers/profiles/keys_controller_spec.rb b/spec/controllers/profiles/keys_controller_spec.rb index 753eb432c5e..3bed117deb0 100644 --- a/spec/controllers/profiles/keys_controller_spec.rb +++ b/spec/controllers/profiles/keys_controller_spec.rb @@ -10,7 +10,7 @@ describe Profiles::KeysController do it "does not generally work" do get :get_keys, params: { username: 'not-existent' } - expect(response).not_to be_success + expect(response).not_to be_successful end end @@ -18,7 +18,7 @@ describe Profiles::KeysController do it "does generally work" do get :get_keys, params: { username: user.username } - expect(response).to be_success + expect(response).to be_successful end it "renders all keys separated with a new line" do @@ -41,7 +41,7 @@ describe Profiles::KeysController do it "does generally work" do get :get_keys, params: { username: user.username } - expect(response).to be_success + expect(response).to be_successful end it "renders all non deploy keys separated with a new line" do diff --git a/spec/controllers/projects/ci/lints_controller_spec.rb b/spec/controllers/projects/ci/lints_controller_spec.rb index 96e82b7086c..14128fb5b0e 100644 --- a/spec/controllers/projects/ci/lints_controller_spec.rb +++ b/spec/controllers/projects/ci/lints_controller_spec.rb @@ -20,9 +20,7 @@ describe Projects::Ci::LintsController do get :show, params: { namespace_id: project.namespace, project_id: project } end - it 'is success' do - expect(response).to be_success - end + it { expect(response).to be_successful } it 'renders show page' do expect(response).to render_template :show @@ -78,9 +76,7 @@ describe Projects::Ci::LintsController do post :create, params: { namespace_id: project.namespace, project_id: project, content: content } end - it 'is success' do - expect(response).to be_success - end + it { expect(response).to be_successful } it 'render show page' do expect(response).to render_template :show diff --git a/spec/controllers/projects/commit_controller_spec.rb b/spec/controllers/projects/commit_controller_spec.rb index 58a1d96d010..afd5cb15e0f 100644 --- a/spec/controllers/projects/commit_controller_spec.rb +++ b/spec/controllers/projects/commit_controller_spec.rb @@ -45,14 +45,14 @@ describe Projects::CommitController do it 'handles binary files' do go(id: TestEnv::BRANCH_SHA['binary-encoding'], format: 'html') - expect(response).to be_success + expect(response).to be_successful end shared_examples "export as" do |format| it "does generally work" do go(id: commit.id, format: format) - expect(response).to be_success + expect(response).to be_successful end it "generates it" do @@ -110,7 +110,7 @@ describe Projects::CommitController do id: commit.id }) - expect(response).to be_success + expect(response).to be_successful end end @@ -177,7 +177,7 @@ describe Projects::CommitController do id: commit.id }) - expect(response).not_to be_success + expect(response).not_to be_successful expect(response).to have_gitlab_http_status(404) end end @@ -234,7 +234,7 @@ describe Projects::CommitController do id: master_pickable_commit.id }) - expect(response).not_to be_success + expect(response).not_to be_successful expect(response).to have_gitlab_http_status(404) end end diff --git a/spec/controllers/projects/commits_controller_spec.rb b/spec/controllers/projects/commits_controller_spec.rb index 9db1ac2a46c..9c4d6fdcb2a 100644 --- a/spec/controllers/projects/commits_controller_spec.rb +++ b/spec/controllers/projects/commits_controller_spec.rb @@ -79,7 +79,7 @@ describe Projects::CommitsController do end it "renders as atom" do - expect(response).to be_success + expect(response).to be_successful expect(response.content_type).to eq('application/atom+xml') end @@ -104,7 +104,7 @@ describe Projects::CommitsController do end it "renders as HTML" do - expect(response).to be_success + expect(response).to be_successful expect(response.content_type).to eq('text/html') end end diff --git a/spec/controllers/projects/compare_controller_spec.rb b/spec/controllers/projects/compare_controller_spec.rb index 48a92a772dc..9afc46c4be9 100644 --- a/spec/controllers/projects/compare_controller_spec.rb +++ b/spec/controllers/projects/compare_controller_spec.rb @@ -19,7 +19,7 @@ describe Projects::CompareController do end it 'returns successfully' do - expect(response).to be_success + expect(response).to be_successful end end @@ -49,7 +49,7 @@ describe Projects::CompareController do it 'shows some diffs with ignore whitespace change option' do show_request - expect(response).to be_success + expect(response).to be_successful diff_file = assigns(:diffs).diff_files.first expect(diff_file).not_to be_nil expect(assigns(:commits).length).to be >= 1 @@ -67,7 +67,7 @@ describe Projects::CompareController do it 'sets the diffs and commits ivars' do show_request - expect(response).to be_success + expect(response).to be_successful expect(assigns(:diffs).diff_files.first).not_to be_nil expect(assigns(:commits).length).to be >= 1 end @@ -81,7 +81,7 @@ describe Projects::CompareController do it 'sets empty diff and commit ivars' do show_request - expect(response).to be_success + expect(response).to be_successful expect(assigns(:diffs)).to eq([]) expect(assigns(:commits)).to eq([]) end @@ -94,7 +94,7 @@ describe Projects::CompareController do it 'sets empty diff and commit ivars' do show_request - expect(response).to be_success + expect(response).to be_successful expect(assigns(:diffs)).to eq([]) expect(assigns(:commits)).to eq([]) end diff --git a/spec/controllers/projects/cycle_analytics/events_controller_spec.rb b/spec/controllers/projects/cycle_analytics/events_controller_spec.rb index 8fc3ae0aa32..b828c678d0c 100644 --- a/spec/controllers/projects/cycle_analytics/events_controller_spec.rb +++ b/spec/controllers/projects/cycle_analytics/events_controller_spec.rb @@ -16,7 +16,7 @@ describe Projects::CycleAnalytics::EventsController do it 'is empty' do get_issue - expect(response).to be_success + expect(response).to be_successful expect(JSON.parse(response.body)['events']).to be_empty end end @@ -32,7 +32,7 @@ describe Projects::CycleAnalytics::EventsController do it 'is not empty' do get_issue - expect(response).to be_success + expect(response).to be_successful end it 'contains event detais' do @@ -49,7 +49,7 @@ describe Projects::CycleAnalytics::EventsController do it 'is empty' do get_issue(additional_params: { cycle_analytics: { start_date: 7 } }) - expect(response).to be_success + expect(response).to be_successful expect(JSON.parse(response.body)['events']).to be_empty end diff --git a/spec/controllers/projects/cycle_analytics_controller_spec.rb b/spec/controllers/projects/cycle_analytics_controller_spec.rb index 5e6ceef2517..65eee7b8ead 100644 --- a/spec/controllers/projects/cycle_analytics_controller_spec.rb +++ b/spec/controllers/projects/cycle_analytics_controller_spec.rb @@ -21,7 +21,7 @@ describe Projects::CycleAnalyticsController do project_id: project }) - expect(response).to be_success + expect(response).to be_successful end end @@ -34,7 +34,7 @@ describe Projects::CycleAnalyticsController do project_id: project }) - expect(response).to be_success + expect(response).to be_successful expect(assigns(:cycle_analytics_no_data)).to eq(true) end end @@ -55,7 +55,7 @@ describe Projects::CycleAnalyticsController do project_id: project }) - expect(response).to be_success + expect(response).to be_successful expect(assigns(:cycle_analytics_no_data)).to eq(false) end end diff --git a/spec/controllers/projects/merge_requests/creations_controller_spec.rb b/spec/controllers/projects/merge_requests/creations_controller_spec.rb index 3816e1c7a31..ce977f26ec6 100644 --- a/spec/controllers/projects/merge_requests/creations_controller_spec.rb +++ b/spec/controllers/projects/merge_requests/creations_controller_spec.rb @@ -28,7 +28,7 @@ describe Projects::MergeRequests::CreationsController do it 'renders new merge request widget template' do get :new, params: get_diff_params - expect(response).to be_success + expect(response).to be_successful end end @@ -56,7 +56,7 @@ describe Projects::MergeRequests::CreationsController do it 'limits total commits' do get :new, params: large_diff_params - expect(response).to be_success + expect(response).to be_successful total = assigns(:total_commit_count) expect(assigns(:commits)).to be_an Array @@ -70,7 +70,7 @@ describe Projects::MergeRequests::CreationsController do it 'shows total commits' do get :new, params: large_diff_params - expect(response).to be_success + expect(response).to be_successful total = assigns(:total_commit_count) expect(assigns(:commits)).to be_an CommitCollection @@ -89,7 +89,7 @@ describe Projects::MergeRequests::CreationsController do get :diffs, params: get_diff_params.merge(format: 'json') - expect(response).to be_success + expect(response).to be_successful expect(assigns[:diffs]).to be_nil end end diff --git a/spec/controllers/projects/merge_requests/diffs_controller_spec.rb b/spec/controllers/projects/merge_requests/diffs_controller_spec.rb index d940d226176..ac3e9901123 100644 --- a/spec/controllers/projects/merge_requests/diffs_controller_spec.rb +++ b/spec/controllers/projects/merge_requests/diffs_controller_spec.rb @@ -66,7 +66,7 @@ describe Projects::MergeRequests::DiffsController do end it 'renders' do - expect(response).to be_success + expect(response).to be_successful expect(response.body).to have_content('Subproject commit') end end diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb index b1dc6a65dd4..11b1eaf11b7 100644 --- a/spec/controllers/projects/merge_requests_controller_spec.rb +++ b/spec/controllers/projects/merge_requests_controller_spec.rb @@ -57,7 +57,7 @@ describe Projects::MergeRequestsController do go(format: :html) - expect(response).to be_success + expect(response).to be_successful end end @@ -66,7 +66,7 @@ describe Projects::MergeRequestsController do go(format: :html) - expect(response).to be_success + expect(response).to be_successful end context "that is invalid" do @@ -75,7 +75,7 @@ describe Projects::MergeRequestsController do it "renders merge request page" do go(format: :html) - expect(response).to be_success + expect(response).to be_successful end end end @@ -124,7 +124,7 @@ describe Projects::MergeRequestsController do it "renders merge request page" do go(format: :json) - expect(response).to be_success + expect(response).to be_successful end end end diff --git a/spec/controllers/projects/milestones_controller_spec.rb b/spec/controllers/projects/milestones_controller_spec.rb index 9b2025b836c..cbf9d437909 100644 --- a/spec/controllers/projects/milestones_controller_spec.rb +++ b/spec/controllers/projects/milestones_controller_spec.rb @@ -139,7 +139,7 @@ describe Projects::MilestonesController do expect(issue.milestone_id).to eq(milestone.id) delete :destroy, params: { namespace_id: project.namespace.id, project_id: project.id, id: milestone.iid }, format: :js - expect(response).to be_success + expect(response).to be_successful expect(Event.recent.first.action).to eq(Event::DESTROYED) diff --git a/spec/controllers/projects/pipelines_controller_spec.rb b/spec/controllers/projects/pipelines_controller_spec.rb index 9a50ea79f5e..089d06e11eb 100644 --- a/spec/controllers/projects/pipelines_controller_spec.rb +++ b/spec/controllers/projects/pipelines_controller_spec.rb @@ -177,18 +177,22 @@ describe Projects::PipelinesController do end it 'does not perform N + 1 queries' do + # Set up all required variables + get_pipeline_json + control_count = ActiveRecord::QueryRecorder.new { get_pipeline_json }.count - create_build('test', 1, 'rspec 1') - create_build('test', 1, 'spinach 0') - create_build('test', 1, 'spinach 1') - create_build('test', 1, 'audit') - create_build('post deploy', 3, 'pages 1') - create_build('post deploy', 3, 'pages 2') + first_build = pipeline.builds.first + first_build.tag_list << [:hello, :world] + create(:deployment, deployable: first_build) + + second_build = pipeline.builds.second + second_build.tag_list << [:docker, :ruby] + create(:deployment, deployable: second_build) new_count = ActiveRecord::QueryRecorder.new { get_pipeline_json }.count - expect(new_count).to be_within(12).of(control_count) + expect(new_count).to be_within(1).of(control_count) end end diff --git a/spec/controllers/projects/project_members_controller_spec.rb b/spec/controllers/projects/project_members_controller_spec.rb index 4141e41c7a7..5130e26c928 100644 --- a/spec/controllers/projects/project_members_controller_spec.rb +++ b/spec/controllers/projects/project_members_controller_spec.rb @@ -158,7 +158,7 @@ describe Projects::ProjectMembersController do id: member }, xhr: true - expect(response).to be_success + expect(response).to be_successful expect(project.members).not_to include member end end diff --git a/spec/controllers/projects/raw_controller_spec.rb b/spec/controllers/projects/raw_controller_spec.rb index b958f419a19..8b43d1264b2 100644 --- a/spec/controllers/projects/raw_controller_spec.rb +++ b/spec/controllers/projects/raw_controller_spec.rb @@ -67,9 +67,9 @@ describe Projects::RawController do attributes = { message: 'Action_Rate_Limiter_Request', env: :raw_blob_request_limit, - ip: '0.0.0.0', + remote_ip: '0.0.0.0', request_method: 'GET', - fullpath: "/#{project.full_path}/raw/#{file_path}" + path: "/#{project.full_path}/raw/#{file_path}" } expect(Gitlab::AuthLogger).to receive(:error).with(attributes).once diff --git a/spec/controllers/projects/refs_controller_spec.rb b/spec/controllers/projects/refs_controller_spec.rb index 6db98f2428b..646c7a7db7c 100644 --- a/spec/controllers/projects/refs_controller_spec.rb +++ b/spec/controllers/projects/refs_controller_spec.rb @@ -49,7 +49,7 @@ describe Projects::RefsController do expect(::Gitlab::GitalyClient).to receive(:allow_ref_name_caching).and_call_original xhr_get(:js) - expect(response).to be_success + expect(response).to be_successful end it 'renders JSON' do @@ -57,7 +57,7 @@ describe Projects::RefsController do xhr_get(:json) - expect(response).to be_success + expect(response).to be_successful expect(json_response).to be_kind_of(Array) end end diff --git a/spec/controllers/projects/services_controller_spec.rb b/spec/controllers/projects/services_controller_spec.rb index 68eabce8513..563b61962cf 100644 --- a/spec/controllers/projects/services_controller_spec.rb +++ b/spec/controllers/projects/services_controller_spec.rb @@ -159,7 +159,7 @@ describe Projects::ServicesController do context 'with approved services' do it 'renders edit page' do - expect(response).to be_success + expect(response).to be_successful end end end diff --git a/spec/controllers/projects/starrers_controller_spec.rb b/spec/controllers/projects/starrers_controller_spec.rb index 7085cba08d5..5774ff7c576 100644 --- a/spec/controllers/projects/starrers_controller_spec.rb +++ b/spec/controllers/projects/starrers_controller_spec.rb @@ -32,6 +32,20 @@ describe Projects::StarrersController do end end + context 'N+1 queries' do + render_views + + it 'avoids N+1s loading users', :request_store do + get_starrers + + control_count = ActiveRecord::QueryRecorder.new { get_starrers }.count + + create_list(:user, 5).each { |user| user.toggle_star(project) } + + expect { get_starrers }.not_to exceed_query_limit(control_count) + end + end + context 'when project is public' do before do project.update_attribute(:visibility_level, Project::PUBLIC) diff --git a/spec/controllers/registrations_controller_spec.rb b/spec/controllers/registrations_controller_spec.rb index fed4fc810f2..35487682462 100644 --- a/spec/controllers/registrations_controller_spec.rb +++ b/spec/controllers/registrations_controller_spec.rb @@ -129,9 +129,9 @@ describe RegistrationsController do { message: auth_log_message, env: :invisible_captcha_signup_bot_detected, - ip: '0.0.0.0', + remote_ip: '0.0.0.0', request_method: 'POST', - fullpath: '/users' + path: '/users' } end diff --git a/spec/controllers/users_controller_spec.rb b/spec/controllers/users_controller_spec.rb index 8b8d4c57000..5566df0c216 100644 --- a/spec/controllers/users_controller_spec.rb +++ b/spec/controllers/users_controller_spec.rb @@ -19,7 +19,7 @@ describe UsersController do it 'renders the show template' do get :show, params: { username: user.username } - expect(response).to be_success + expect(response).to be_successful expect(response).to render_template('show') end end @@ -362,7 +362,7 @@ describe UsersController do it 'responds with success' do get :show, params: { username: user.username } - expect(response).to be_success + expect(response).to be_successful end end @@ -418,7 +418,7 @@ describe UsersController do it 'responds with success' do get :projects, params: { username: user.username } - expect(response).to be_success + expect(response).to be_successful end end diff --git a/spec/features/search/user_searches_for_code_spec.rb b/spec/features/search/user_searches_for_code_spec.rb index 5a60991c1bf..4ca79ccaea8 100644 --- a/spec/features/search/user_searches_for_code_spec.rb +++ b/spec/features/search/user_searches_for_code_spec.rb @@ -39,17 +39,16 @@ describe 'User searches for code' do context 'when on a project page', :js do before do visit(search_path) - end - - include_examples 'top right search form' - - it 'finds code' do find('.js-search-project-dropdown').click page.within('.project-filter') do click_link(project.full_name) end + end + include_examples 'top right search form' + + it 'finds code' do fill_in('dashboard_search', with: 'rspec') find('.btn-search').click @@ -57,6 +56,27 @@ describe 'User searches for code' do expect(find(:css, '.search-results')).to have_content('Update capybara, rspec-rails, poltergeist to recent versions') end end + + it 'search mutiple words with refs switching' do + expected_result = 'Use `snake_case` for naming files' + search = 'for naming files' + + fill_in('dashboard_search', with: search) + find('.btn-search').click + + page.within('.results') do + expect(find('.search-results')).to have_content(expected_result) + end + + find('.js-project-refs-dropdown').click + find('.dropdown-page-one .dropdown-content').click_link('v1.0.0') + + page.within('.results') do + expect(find(:css, '.search-results')).to have_content(expected_result) + end + + expect(find_field('dashboard_search').value).to eq(search) + end end context 'search code within refs', :js do diff --git a/spec/fixtures/security-reports/dependency_list/gl-dependency-scanning-report.json b/spec/fixtures/security-reports/dependency_list/gl-dependency-scanning-report.json deleted file mode 100644 index 8fb66f6652b..00000000000 --- a/spec/fixtures/security-reports/dependency_list/gl-dependency-scanning-report.json +++ /dev/null @@ -1,422 +0,0 @@ -{ - "version": "2.1", - "vulnerabilities": [ - { - "category": "dependency_scanning", - "name": "Vulnerabilities in libxml2", - "message": "Vulnerabilities in libxml2 in nokogiri", - "description": " The version of libxml2 packaged with Nokogiri contains several vulnerabilities.\r\n Nokogiri has mitigated these issues by upgrading to libxml 2.9.5.\r\n\r\n It was discovered that a type confusion error existed in libxml2. An\r\n attacker could use this to specially construct XML data that\r\n could cause a denial of service or possibly execute arbitrary\r\n code. (CVE-2017-0663)\r\n\r\n It was discovered that libxml2 did not properly validate parsed entity\r\n references. An attacker could use this to specially construct XML\r\n data that could expose sensitive information. (CVE-2017-7375)\r\n\r\n It was discovered that a buffer overflow existed in libxml2 when\r\n handling HTTP redirects. An attacker could use this to specially\r\n construct XML data that could cause a denial of service or possibly\r\n execute arbitrary code. (CVE-2017-7376)\r\n\r\n Marcel Böhme and Van-Thuan Pham discovered a buffer overflow in\r\n libxml2 when handling elements. An attacker could use this to specially\r\n construct XML data that could cause a denial of service or possibly\r\n execute arbitrary code. (CVE-2017-9047)\r\n\r\n Marcel Böhme and Van-Thuan Pham discovered a buffer overread\r\n in libxml2 when handling elements. An attacker could use this\r\n to specially construct XML data that could cause a denial of\r\n service. (CVE-2017-9048)\r\n\r\n Marcel Böhme and Van-Thuan Pham discovered multiple buffer overreads\r\n in libxml2 when handling parameter-entity references. An attacker\r\n could use these to specially construct XML data that could cause a\r\n denial of service. (CVE-2017-9049, CVE-2017-9050)", - "cve": "rails/Gemfile.lock:nokogiri:gemnasium:06565b64-486d-4326-b906-890d9915804d", - "severity": "High", - "solution": "Upgrade to latest version.", - "scanner": { - "id": "gemnasium", - "name": "Gemnasium" - }, - "location": { - "file": "rails/Gemfile.lock", - "dependency": { - "package": { - "name": "nokogiri" - }, - "version": "1.8.0" - } - }, - "identifiers": [ - { - "type": "gemnasium", - "name": "Gemnasium-06565b64-486d-4326-b906-890d9915804d", - "value": "06565b64-486d-4326-b906-890d9915804d", - "url": "https://deps.sec.gitlab.com/packages/gem/nokogiri/versions/1.8.0/advisories" - }, - { - "type": "usn", - "name": "USN-3424-1", - "value": "USN-3424-1", - "url": "https://usn.ubuntu.com/3424-1/" - } - ], - "links": [ - { - "url": "https://github.com/sparklemotion/nokogiri/issues/1673" - } - ] - }, - { - "category": "dependency_scanning", - "name": "Infinite recursion in parameter entities", - "message": "Infinite recursion in parameter entities in nokogiri", - "description": "libxml2 incorrectly handles certain parameter entities. An attacker can leverage this with specially constructed XML data to cause libxml2 to consume resources, leading to a denial of service.", - "cve": "rails/Gemfile.lock:nokogiri:gemnasium:6a0d56f6-2441-492a-9b14-edb95ac31919", - "severity": "High", - "solution": "Upgrade to latest version.", - "scanner": { - "id": "gemnasium", - "name": "Gemnasium" - }, - "location": { - "file": "rails/Gemfile.lock", - "dependency": { - "package": { - "name": "nokogiri" - }, - "version": "1.8.0" - } - }, - "identifiers": [ - { - "type": "gemnasium", - "name": "Gemnasium-6a0d56f6-2441-492a-9b14-edb95ac31919", - "value": "6a0d56f6-2441-492a-9b14-edb95ac31919", - "url": "https://deps.sec.gitlab.com/packages/gem/nokogiri/versions/1.8.0/advisories" - }, - { - "type": "cve", - "name": "CVE-2017-16932", - "value": "CVE-2017-16932", - "url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-16932" - } - ], - "links": [ - { - "url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-16932" - }, - { - "url": "https://github.com/sparklemotion/nokogiri/issues/1714" - }, - { - "url": "https://people.canonical.com/~ubuntu-security/cve/2017/CVE-2017-16932.html" - }, - { - "url": "https://usn.ubuntu.com/usn/usn-3504-1/" - } - ] - }, - { - "category": "dependency_scanning", - "name": "Denial of Service", - "message": "Denial of Service in nokogiri", - "description": "libxml2 incorrectly handles certain files. An attacker can use this issue with specially constructed XML data to cause libxml2 to consume resources, leading to a denial of service.\r\n\r\n", - "cve": "rails/Gemfile.lock:nokogiri:gemnasium:78658378-bd8f-4d79-81c8-07c419302426", - "severity": "Unknown", - "solution": "Upgrade to latest version.", - "scanner": { - "id": "gemnasium", - "name": "Gemnasium" - }, - "location": { - "file": "rails/Gemfile.lock", - "dependency": { - "package": { - "name": "nokogiri" - }, - "version": "1.8.0" - } - }, - "identifiers": [ - { - "type": "gemnasium", - "name": "Gemnasium-78658378-bd8f-4d79-81c8-07c419302426", - "value": "78658378-bd8f-4d79-81c8-07c419302426", - "url": "https://deps.sec.gitlab.com/packages/gem/nokogiri/versions/1.8.0/advisories" - }, - { - "type": "cve", - "name": "CVE-2017-15412", - "value": "CVE-2017-15412", - "url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-15412" - } - ], - "links": [ - { - "url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-15412" - }, - { - "url": "https://github.com/sparklemotion/nokogiri/issues/1714" - }, - { - "url": "https://people.canonical.com/~ubuntu-security/cve/2017/CVE-2017-15412.html" - } - ] - }, - { - "category": "dependency_scanning", - "name": "Bypass of a protection mechanism in libxslt", - "message": "Bypass of a protection mechanism in libxslt in nokogiri", - "description": "libxslt through 1.1.33 allows bypass of a protection mechanism because callers of xsltCheckRead and xsltCheckWrite permit access even upon receiving a -1 error code. xsltCheckRead can return -1 for a crafted URL that is not actually invalid and is subsequently loaded. Vendored version of libxslt has been patched to remediate this vulnerability. Note that this patch is not yet (as of 2019-04-22) in an upstream release of libxslt.", - "cve": "rails/Gemfile.lock:nokogiri:gemnasium:1a2e2e6e-67ba-4142-bfa1-3391f5416e4c", - "severity": "Unknown", - "solution": "Upgrade to latest version if using vendored version of libxslt OR update the system library libxslt to a fixed version", - "scanner": { - "id": "gemnasium", - "name": "Gemnasium" - }, - "location": { - "file": "rails/Gemfile.lock", - "dependency": { - "package": { - "name": "nokogiri" - }, - "version": "1.8.0" - } - }, - "identifiers": [ - { - "type": "gemnasium", - "name": "Gemnasium-1a2e2e6e-67ba-4142-bfa1-3391f5416e4c", - "value": "1a2e2e6e-67ba-4142-bfa1-3391f5416e4c", - "url": "https://deps.sec.gitlab.com/packages/gem/nokogiri/versions/1.8.0/advisories" - }, - { - "type": "cve", - "name": "CVE-2019-11068", - "value": "CVE-2019-11068", - "url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-11068" - } - ], - "links": [ - { - "url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-11068" - }, - { - "url": "https://github.com/sparklemotion/nokogiri/issues/1892" - }, - { - "url": "https://people.canonical.com/~ubuntu-security/cve/CVE-2019-11068" - }, - { - "url": "https://security-tracker.debian.org/tracker/CVE-2019-11068" - } - ] - }, - { - "category": "dependency_scanning", - "name": "Regular Expression Denial of Service", - "message": "Regular Expression Denial of Service in debug", - "description": "The debug module is vulnerable to regular expression denial of service when untrusted user input is passed into the `o` formatter. It takes around 50k characters to block for 2 seconds making this a low severity issue.", - "cve": "yarn/yarn.lock:debug:gemnasium:37283ed4-0380-40d7-ada7-2d994afcc62a", - "severity": "Unknown", - "solution": "Upgrade to latest versions.", - "scanner": { - "id": "gemnasium", - "name": "Gemnasium" - }, - "location": { - "file": "yarn/yarn.lock", - "dependency": { - "package": { - "name": "debug" - }, - "version": "1.0.5" - } - }, - "identifiers": [ - { - "type": "gemnasium", - "name": "Gemnasium-37283ed4-0380-40d7-ada7-2d994afcc62a", - "value": "37283ed4-0380-40d7-ada7-2d994afcc62a", - "url": "https://deps.sec.gitlab.com/packages/npm/debug/versions/1.0.5/advisories" - } - ], - "links": [ - { - "url": "https://github.com/visionmedia/debug/issues/501" - }, - { - "url": "https://github.com/visionmedia/debug/pull/504" - }, - { - "url": "https://nodesecurity.io/advisories/534" - } - ] - }, - { - "category": "dependency_scanning", - "name": "Authentication bypass via incorrect DOM traversal and canonicalization", - "message": "Authentication bypass via incorrect DOM traversal and canonicalization in saml2-js", - "description": "Some XML DOM traversal and canonicalization APIs may be inconsistent in handling of comments within XML nodes. Incorrect use of these APIs by some SAML libraries results in incorrect parsing of the inner text of XML nodes such that any inner text after the comment is lost prior to cryptographically signing the SAML message. Text after the comment therefore has no impact on the signature on the SAML message.\r\n\r\nA remote attacker can modify SAML content for a SAML service provider without invalidating the cryptographic signature, which may allow attackers to bypass primary authentication for the affected SAML service provider.", - "cve": "yarn/yarn.lock:saml2-js:gemnasium:9952e574-7b5b-46fa-a270-aeb694198a98", - "severity": "Unknown", - "solution": "Upgrade to fixed version.\r\n", - "scanner": { - "id": "gemnasium", - "name": "Gemnasium" - }, - "location": { - "file": "yarn/yarn.lock", - "dependency": { - "package": { - "name": "saml2-js" - }, - "version": "1.5.0" - } - }, - "identifiers": [ - { - "type": "gemnasium", - "name": "Gemnasium-9952e574-7b5b-46fa-a270-aeb694198a98", - "value": "9952e574-7b5b-46fa-a270-aeb694198a98", - "url": "https://deps.sec.gitlab.com/packages/npm/saml2-js/versions/1.5.0/advisories" - }, - { - "type": "cve", - "name": "CVE-2017-11429", - "value": "CVE-2017-11429", - "url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-11429" - } - ], - "links": [ - { - "url": "https://github.com/Clever/saml2/commit/3546cb61fd541f219abda364c5b919633609ef3d#diff-af730f9f738de1c9ad87596df3f6de84R279" - }, - { - "url": "https://github.com/Clever/saml2/issues/127" - }, - { - "url": "https://www.kb.cert.org/vuls/id/475445" - } - ] - } - ], - "remediations": [], - "dependency_files": [ - { - "path": "rails/Gemfile.lock", - "package_manager": "bundler", - "dependencies": [ - { - "package": { - "name": "mini_portile2" - }, - "version": "2.2.0" - }, - { - "package": { - "name": "nokogiri" - }, - "version": "1.8.0" - } - ] - }, - { - "path": "yarn/yarn.lock", - "package_manager": "yarn", - "dependencies": [ - { - "package": { - "name": "async" - }, - "version": "0.2.10" - }, - { - "package": { - "name": "async" - }, - "version": "1.5.2" - }, - { - "package": { - "name": "debug" - }, - "version": "1.0.5" - }, - { - "package": { - "name": "ejs" - }, - "version": "0.8.8" - }, - { - "package": { - "name": "ms" - }, - "version": "2.0.0" - }, - { - "package": { - "name": "node-forge" - }, - "version": "0.2.24" - }, - { - "package": { - "name": "saml2-js" - }, - "version": "1.5.0" - }, - { - "package": { - "name": "sax" - }, - "version": "1.2.4" - }, - { - "package": { - "name": "underscore" - }, - "version": "1.9.1" - }, - { - "package": { - "name": "underscore" - }, - "version": "1.6.0" - }, - { - "package": { - "name": "xml-crypto" - }, - "version": "0.8.5" - }, - { - "package": { - "name": "xml-encryption" - }, - "version": "0.7.4" - }, - { - "package": { - "name": "xml2js" - }, - "version": "0.4.19" - }, - { - "package": { - "name": "xmlbuilder" - }, - "version": "2.1.0" - }, - { - "package": { - "name": "xmlbuilder" - }, - "version": "9.0.7" - }, - { - "package": { - "name": "xmldom" - }, - "version": "0.1.19" - }, - { - "package": { - "name": "xmldom" - }, - "version": "0.1.27" - }, - { - "package": { - "name": "xpath.js" - }, - "version": "1.1.0" - }, - { - "package": { - "name": "xpath" - }, - "version": "0.0.5" - } - ] - } - ] -} diff --git a/spec/fixtures/security-reports/deprecated/gl-dependency-scanning-report.json b/spec/fixtures/security-reports/deprecated/gl-dependency-scanning-report.json deleted file mode 100644 index ce66f562175..00000000000 --- a/spec/fixtures/security-reports/deprecated/gl-dependency-scanning-report.json +++ /dev/null @@ -1,178 +0,0 @@ -[ - { - "category": "dependency_scanning", - "name": "io.netty/netty - CVE-2014-3488", - "message": "DoS by CPU exhaustion when using malicious SSL packets", - "cve": "app/pom.xml:io.netty/netty@3.9.1.Final:CVE-2014-3488", - "severity": "Unknown", - "solution": "Upgrade to the latest version", - "scanner": { - "id": "gemnasium", - "name": "Gemnasium" - }, - "location": { - "file": "app/pom.xml", - "dependency": { - "package": { - "name": "io.netty/netty" - }, - "version": "3.9.1.Final" - } - }, - "identifiers": [ - { - "type": "gemnasium", - "name": "Gemnasium-d1bf36d9-9f07-46cd-9cfc-8675338ada8f", - "value": "d1bf36d9-9f07-46cd-9cfc-8675338ada8f", - "url": "https://deps.sec.gitlab.com/packages/maven/io.netty/netty/versions/3.9.1.Final/advisories" - }, - { - "type": "cve", - "name": "CVE-2014-3488", - "value": "CVE-2014-3488", - "url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-3488" - } - ], - "links": [ - { - "url": "https://bugzilla.redhat.com/CVE-2014-3488" - }, - { - "url": "http://netty.io/news/2014/06/11/3.html" - }, - { - "url": "https://github.com/netty/netty/issues/2562" - } - ], - "priority": "Unknown", - "file": "app/pom.xml", - "url": "https://bugzilla.redhat.com/CVE-2014-3488", - "tool": "gemnasium" - }, - { - "category": "dependency_scanning", - "name": "Django - CVE-2017-12794", - "message": "Possible XSS in traceback section of technical 500 debug page", - "cve": "app/requirements.txt:Django@1.11.3:CVE-2017-12794", - "severity": "Unknown", - "solution": "Upgrade to latest version or apply patch.", - "scanner": { - "id": "gemnasium", - "name": "Gemnasium" - }, - "location": { - "file": "app/requirements.txt", - "dependency": { - "package": { - "name": "Django" - }, - "version": "1.11.3" - } - }, - "identifiers": [ - { - "type": "gemnasium", - "name": "Gemnasium-6162a015-8635-4a15-8d7c-dc9321db366f", - "value": "6162a015-8635-4a15-8d7c-dc9321db366f", - "url": "https://deps.sec.gitlab.com/packages/pypi/Django/versions/1.11.3/advisories" - }, - { - "type": "cve", - "name": "CVE-2017-12794", - "value": "CVE-2017-12794", - "url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-12794" - } - ], - "links": [ - { - "url": "https://www.djangoproject.com/weblog/2017/sep/05/security-releases/" - } - ], - "priority": "Unknown", - "file": "app/requirements.txt", - "url": "https://www.djangoproject.com/weblog/2017/sep/05/security-releases/", - "tool": "gemnasium" - }, - { - "category": "dependency_scanning", - "name": "nokogiri - USN-3424-1", - "message": "Vulnerabilities in libxml2", - "cve": "rails/Gemfile.lock:nokogiri@1.8.0:USN-3424-1", - "severity": "Unknown", - "solution": "Upgrade to latest version.", - "scanner": { - "id": "gemnasium", - "name": "Gemnasium" - }, - "location": { - "file": "rails/Gemfile.lock", - "dependency": { - "package": { - "name": "nokogiri" - }, - "version": "1.8.0" - } - }, - "identifiers": [ - { - "type": "gemnasium", - "name": "Gemnasium-06565b64-486d-4326-b906-890d9915804d", - "value": "06565b64-486d-4326-b906-890d9915804d", - "url": "https://deps.sec.gitlab.com/packages/gem/nokogiri/versions/1.8.0/advisories" - }, - { - "type": "usn", - "name": "USN-3424-1", - "value": "USN-3424-1", - "url": "https://usn.ubuntu.com/3424-1/" - } - ], - "links": [ - { - "url": "https://github.com/sparklemotion/nokogiri/issues/1673" - } - ], - "priority": "Unknown", - "file": "rails/Gemfile.lock", - "url": "https://github.com/sparklemotion/nokogiri/issues/1673", - "tool": "gemnasium" - }, - { - "category": "dependency_scanning", - "name": "ffi - CVE-2018-1000201", - "message": "ruby-ffi DDL loading issue on Windows OS", - "cve": "ffi:1.9.18:CVE-2018-1000201", - "severity": "High", - "solution": "upgrade to \u003e= 1.9.24", - "scanner": { - "id": "bundler_audit", - "name": "bundler-audit" - }, - "location": { - "file": "sast-sample-rails/Gemfile.lock", - "dependency": { - "package": { - "name": "ffi" - }, - "version": "1.9.18" - } - }, - "identifiers": [ - { - "type": "cve", - "name": "CVE-2018-1000201", - "value": "CVE-2018-1000201", - "url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-1000201" - } - ], - "links": [ - { - "url": "https://github.com/ffi/ffi/releases/tag/1.9.24" - } - ], - "priority": "High", - "file": "sast-sample-rails/Gemfile.lock", - "url": "https://github.com/ffi/ffi/releases/tag/1.9.24", - "tool": "bundler_audit" - } -] diff --git a/spec/fixtures/security-reports/deprecated/gl-sast-report.json b/spec/fixtures/security-reports/deprecated/gl-sast-report.json deleted file mode 100644 index 2f7e47281e2..00000000000 --- a/spec/fixtures/security-reports/deprecated/gl-sast-report.json +++ /dev/null @@ -1,964 +0,0 @@ -[ - { - "category": "sast", - "message": "Probable insecure usage of temp file/directory.", - "cve": "python/hardcoded/hardcoded-tmp.py:52865813c884a507be1f152d654245af34aba8a391626d01f1ab6d3f52ec8779:B108", - "severity": "Medium", - "confidence": "Medium", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/hardcoded/hardcoded-tmp.py", - "start_line": 1, - "end_line": 1 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B108", - "value": "B108", - "url": "https://docs.openstack.org/bandit/latest/plugins/b108_hardcoded_tmp_directory.html" - } - ], - "priority": "Medium", - "file": "python/hardcoded/hardcoded-tmp.py", - "line": 1, - "url": "https://docs.openstack.org/bandit/latest/plugins/b108_hardcoded_tmp_directory.html", - "tool": "bandit" - }, - { - "category": "sast", - "name": "Predictable pseudorandom number generator", - "message": "Predictable pseudorandom number generator", - "cve": "groovy/src/main/java/com/gitlab/security_products/tests/App.groovy:47:PREDICTABLE_RANDOM", - "severity": "Medium", - "confidence": "Medium", - "scanner": { - "id": "find_sec_bugs", - "name": "Find Security Bugs" - }, - "location": { - "file": "groovy/src/main/java/com/gitlab/security_products/tests/App.groovy", - "start_line": 47, - "end_line": 47, - "class": "com.gitlab.security_products.tests.App", - "method": "generateSecretToken2" - }, - "identifiers": [ - { - "type": "find_sec_bugs_type", - "name": "Find Security Bugs-PREDICTABLE_RANDOM", - "value": "PREDICTABLE_RANDOM", - "url": "https://find-sec-bugs.github.io/bugs.htm#PREDICTABLE_RANDOM" - } - ], - "priority": "Medium", - "file": "groovy/src/main/java/com/gitlab/security_products/tests/App.groovy", - "line": 47, - "url": "https://find-sec-bugs.github.io/bugs.htm#PREDICTABLE_RANDOM", - "tool": "find_sec_bugs" - }, - { - "category": "sast", - "name": "Predictable pseudorandom number generator", - "message": "Predictable pseudorandom number generator", - "cve": "groovy/src/main/java/com/gitlab/security_products/tests/App.groovy:41:PREDICTABLE_RANDOM", - "severity": "Medium", - "confidence": "Medium", - "scanner": { - "id": "find_sec_bugs", - "name": "Find Security Bugs" - }, - "location": { - "file": "groovy/src/main/java/com/gitlab/security_products/tests/App.groovy", - "start_line": 41, - "end_line": 41, - "class": "com.gitlab.security_products.tests.App", - "method": "generateSecretToken1" - }, - "identifiers": [ - { - "type": "find_sec_bugs_type", - "name": "Find Security Bugs-PREDICTABLE_RANDOM", - "value": "PREDICTABLE_RANDOM", - "url": "https://find-sec-bugs.github.io/bugs.htm#PREDICTABLE_RANDOM" - } - ], - "priority": "Medium", - "file": "groovy/src/main/java/com/gitlab/security_products/tests/App.groovy", - "line": 41, - "url": "https://find-sec-bugs.github.io/bugs.htm#PREDICTABLE_RANDOM", - "tool": "find_sec_bugs" - }, - { - "category": "sast", - "message": "Use of insecure MD2, MD4, or MD5 hash function.", - "cve": "python/imports/imports-aliases.py:cb203b465dffb0cb3a8e8bd8910b84b93b0a5995a938e4b903dbb0cd6ffa1254:B303", - "severity": "Medium", - "confidence": "High", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/imports/imports-aliases.py", - "start_line": 11, - "end_line": 11 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B303", - "value": "B303" - } - ], - "priority": "Medium", - "file": "python/imports/imports-aliases.py", - "line": 11, - "tool": "bandit" - }, - { - "category": "sast", - "message": "Use of insecure MD2, MD4, or MD5 hash function.", - "cve": "python/imports/imports-aliases.py:a7173c43ae66bd07466632d819d450e0071e02dbf782763640d1092981f9631b:B303", - "severity": "Medium", - "confidence": "High", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/imports/imports-aliases.py", - "start_line": 12, - "end_line": 12 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B303", - "value": "B303" - } - ], - "priority": "Medium", - "file": "python/imports/imports-aliases.py", - "line": 12, - "tool": "bandit" - }, - { - "category": "sast", - "message": "Use of insecure MD2, MD4, or MD5 hash function.", - "cve": "python/imports/imports-aliases.py:017017b77deb0b8369b6065947833eeea752a92ec8a700db590fece3e934cf0d:B303", - "severity": "Medium", - "confidence": "High", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/imports/imports-aliases.py", - "start_line": 13, - "end_line": 13 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B303", - "value": "B303" - } - ], - "priority": "Medium", - "file": "python/imports/imports-aliases.py", - "line": 13, - "tool": "bandit" - }, - { - "category": "sast", - "message": "Use of insecure MD2, MD4, or MD5 hash function.", - "cve": "python/imports/imports-aliases.py:45fc8c53aea7b84f06bc4e590cc667678d6073c4c8a1d471177ca2146fb22db2:B303", - "severity": "Medium", - "confidence": "High", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/imports/imports-aliases.py", - "start_line": 14, - "end_line": 14 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B303", - "value": "B303" - } - ], - "priority": "Medium", - "file": "python/imports/imports-aliases.py", - "line": 14, - "tool": "bandit" - }, - { - "category": "sast", - "message": "Pickle library appears to be in use, possible security issue.", - "cve": "python/imports/imports-aliases.py:5f200d47291e7bbd8352db23019b85453ca048dd98ea0c291260fa7d009963a4:B301", - "severity": "Medium", - "confidence": "High", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/imports/imports-aliases.py", - "start_line": 15, - "end_line": 15 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B301", - "value": "B301" - } - ], - "priority": "Medium", - "file": "python/imports/imports-aliases.py", - "line": 15, - "tool": "bandit" - }, - { - "category": "sast", - "name": "ECB mode is insecure", - "message": "ECB mode is insecure", - "cve": "groovy/src/main/java/com/gitlab/security_products/tests/App.groovy:29:ECB_MODE", - "severity": "Medium", - "confidence": "High", - "scanner": { - "id": "find_sec_bugs", - "name": "Find Security Bugs" - }, - "location": { - "file": "groovy/src/main/java/com/gitlab/security_products/tests/App.groovy", - "start_line": 29, - "end_line": 29, - "class": "com.gitlab.security_products.tests.App", - "method": "insecureCypher" - }, - "identifiers": [ - { - "type": "find_sec_bugs_type", - "name": "Find Security Bugs-ECB_MODE", - "value": "ECB_MODE", - "url": "https://find-sec-bugs.github.io/bugs.htm#ECB_MODE" - } - ], - "priority": "Medium", - "file": "groovy/src/main/java/com/gitlab/security_products/tests/App.groovy", - "line": 29, - "url": "https://find-sec-bugs.github.io/bugs.htm#ECB_MODE", - "tool": "find_sec_bugs" - }, - { - "category": "sast", - "name": "Cipher with no integrity", - "message": "Cipher with no integrity", - "cve": "groovy/src/main/java/com/gitlab/security_products/tests/App.groovy:29:CIPHER_INTEGRITY", - "severity": "Medium", - "confidence": "High", - "scanner": { - "id": "find_sec_bugs", - "name": "Find Security Bugs" - }, - "location": { - "file": "groovy/src/main/java/com/gitlab/security_products/tests/App.groovy", - "start_line": 29, - "end_line": 29, - "class": "com.gitlab.security_products.tests.App", - "method": "insecureCypher" - }, - "identifiers": [ - { - "type": "find_sec_bugs_type", - "name": "Find Security Bugs-CIPHER_INTEGRITY", - "value": "CIPHER_INTEGRITY", - "url": "https://find-sec-bugs.github.io/bugs.htm#CIPHER_INTEGRITY" - } - ], - "priority": "Medium", - "file": "groovy/src/main/java/com/gitlab/security_products/tests/App.groovy", - "line": 29, - "url": "https://find-sec-bugs.github.io/bugs.htm#CIPHER_INTEGRITY", - "tool": "find_sec_bugs" - }, - { - "category": "sast", - "message": "Probable insecure usage of temp file/directory.", - "cve": "python/hardcoded/hardcoded-tmp.py:63dd4d626855555b816985d82c4614a790462a0a3ada89dc58eb97f9c50f3077:B108", - "severity": "Medium", - "confidence": "Medium", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/hardcoded/hardcoded-tmp.py", - "start_line": 14, - "end_line": 14 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B108", - "value": "B108", - "url": "https://docs.openstack.org/bandit/latest/plugins/b108_hardcoded_tmp_directory.html" - } - ], - "priority": "Medium", - "file": "python/hardcoded/hardcoded-tmp.py", - "line": 14, - "url": "https://docs.openstack.org/bandit/latest/plugins/b108_hardcoded_tmp_directory.html", - "tool": "bandit" - }, - { - "category": "sast", - "message": "Probable insecure usage of temp file/directory.", - "cve": "python/hardcoded/hardcoded-tmp.py:4ad6d4c40a8c263fc265f3384724014e0a4f8dd6200af83e51ff120420038031:B108", - "severity": "Medium", - "confidence": "Medium", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/hardcoded/hardcoded-tmp.py", - "start_line": 10, - "end_line": 10 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B108", - "value": "B108", - "url": "https://docs.openstack.org/bandit/latest/plugins/b108_hardcoded_tmp_directory.html" - } - ], - "priority": "Medium", - "file": "python/hardcoded/hardcoded-tmp.py", - "line": 10, - "url": "https://docs.openstack.org/bandit/latest/plugins/b108_hardcoded_tmp_directory.html", - "tool": "bandit" - }, - { - "category": "sast", - "message": "Consider possible security implications associated with Popen module.", - "cve": "python/imports/imports-aliases.py:2c3e1fa1e54c3c6646e8bcfaee2518153c6799b77587ff8d9a7b0631f6d34785:B404", - "severity": "Low", - "confidence": "High", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/imports/imports-aliases.py", - "start_line": 1, - "end_line": 1 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B404", - "value": "B404" - } - ], - "priority": "Low", - "file": "python/imports/imports-aliases.py", - "line": 1, - "tool": "bandit" - }, - { - "category": "sast", - "message": "Consider possible security implications associated with pickle module.", - "cve": "python/imports/imports.py:af58d07f6ad519ef5287fcae65bf1a6999448a1a3a8bc1ac2a11daa80d0b96bf:B403", - "severity": "Low", - "confidence": "High", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/imports/imports.py", - "start_line": 2, - "end_line": 2 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B403", - "value": "B403" - } - ], - "priority": "Low", - "file": "python/imports/imports.py", - "line": 2, - "tool": "bandit" - }, - { - "category": "sast", - "message": "Consider possible security implications associated with subprocess module.", - "cve": "python/imports/imports.py:8de9bc98029d212db530785a5f6780cfa663548746ff228ab8fa96c5bb82f089:B404", - "severity": "Low", - "confidence": "High", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/imports/imports.py", - "start_line": 4, - "end_line": 4 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B404", - "value": "B404" - } - ], - "priority": "Low", - "file": "python/imports/imports.py", - "line": 4, - "tool": "bandit" - }, - { - "category": "sast", - "message": "Possible hardcoded password: 'blerg'", - "cve": "python/hardcoded/hardcoded-passwords.py:97c30f1d76d2a88913e3ce9ae74087874d740f87de8af697a9c455f01119f633:B106", - "severity": "Low", - "confidence": "Medium", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/hardcoded/hardcoded-passwords.py", - "start_line": 22, - "end_line": 22 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B106", - "value": "B106", - "url": "https://docs.openstack.org/bandit/latest/plugins/b106_hardcoded_password_funcarg.html" - } - ], - "priority": "Low", - "file": "python/hardcoded/hardcoded-passwords.py", - "line": 22, - "url": "https://docs.openstack.org/bandit/latest/plugins/b106_hardcoded_password_funcarg.html", - "tool": "bandit" - }, - { - "category": "sast", - "message": "Possible hardcoded password: 'root'", - "cve": "python/hardcoded/hardcoded-passwords.py:7431c73a0bc16d94ece2a2e75ef38f302574d42c37ac0c3c38ad0b3bf8a59f10:B105", - "severity": "Low", - "confidence": "Medium", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/hardcoded/hardcoded-passwords.py", - "start_line": 5, - "end_line": 5 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B105", - "value": "B105", - "url": "https://docs.openstack.org/bandit/latest/plugins/b105_hardcoded_password_string.html" - } - ], - "priority": "Low", - "file": "python/hardcoded/hardcoded-passwords.py", - "line": 5, - "url": "https://docs.openstack.org/bandit/latest/plugins/b105_hardcoded_password_string.html", - "tool": "bandit" - }, - { - "category": "sast", - "message": "Possible hardcoded password: ''", - "cve": "python/hardcoded/hardcoded-passwords.py:d2d1857c27caedd49c57bfbcdc23afcc92bd66a22701fcdc632869aab4ca73ee:B105", - "severity": "Low", - "confidence": "Medium", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/hardcoded/hardcoded-passwords.py", - "start_line": 9, - "end_line": 9 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B105", - "value": "B105", - "url": "https://docs.openstack.org/bandit/latest/plugins/b105_hardcoded_password_string.html" - } - ], - "priority": "Low", - "file": "python/hardcoded/hardcoded-passwords.py", - "line": 9, - "url": "https://docs.openstack.org/bandit/latest/plugins/b105_hardcoded_password_string.html", - "tool": "bandit" - }, - { - "category": "sast", - "message": "Possible hardcoded password: 'ajklawejrkl42348swfgkg'", - "cve": "python/hardcoded/hardcoded-passwords.py:fb3866215a61393a5c9c32a3b60e2058171a23219c353f722cbd3567acab21d2:B105", - "severity": "Low", - "confidence": "Medium", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/hardcoded/hardcoded-passwords.py", - "start_line": 13, - "end_line": 13 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B105", - "value": "B105", - "url": "https://docs.openstack.org/bandit/latest/plugins/b105_hardcoded_password_string.html" - } - ], - "priority": "Low", - "file": "python/hardcoded/hardcoded-passwords.py", - "line": 13, - "url": "https://docs.openstack.org/bandit/latest/plugins/b105_hardcoded_password_string.html", - "tool": "bandit" - }, - { - "category": "sast", - "message": "Possible hardcoded password: 'blerg'", - "cve": "python/hardcoded/hardcoded-passwords.py:63c62a8b7e1e5224439bd26b28030585ac48741e28ca64561a6071080c560a5f:B105", - "severity": "Low", - "confidence": "Medium", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/hardcoded/hardcoded-passwords.py", - "start_line": 23, - "end_line": 23 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B105", - "value": "B105", - "url": "https://docs.openstack.org/bandit/latest/plugins/b105_hardcoded_password_string.html" - } - ], - "priority": "Low", - "file": "python/hardcoded/hardcoded-passwords.py", - "line": 23, - "url": "https://docs.openstack.org/bandit/latest/plugins/b105_hardcoded_password_string.html", - "tool": "bandit" - }, - { - "category": "sast", - "message": "Possible hardcoded password: 'blerg'", - "cve": "python/hardcoded/hardcoded-passwords.py:4311b06d08df8fa58229b341c531da8e1a31ec4520597bdff920cd5c098d86f9:B105", - "severity": "Low", - "confidence": "Medium", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/hardcoded/hardcoded-passwords.py", - "start_line": 24, - "end_line": 24 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B105", - "value": "B105", - "url": "https://docs.openstack.org/bandit/latest/plugins/b105_hardcoded_password_string.html" - } - ], - "priority": "Low", - "file": "python/hardcoded/hardcoded-passwords.py", - "line": 24, - "url": "https://docs.openstack.org/bandit/latest/plugins/b105_hardcoded_password_string.html", - "tool": "bandit" - }, - { - "category": "sast", - "message": "Consider possible security implications associated with subprocess module.", - "cve": "python/imports/imports-function.py:5858400c2f39047787702de44d03361ef8d954c9d14bd54ee1c2bef9e6a7df93:B404", - "severity": "Low", - "confidence": "High", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/imports/imports-function.py", - "start_line": 4, - "end_line": 4 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B404", - "value": "B404" - } - ], - "priority": "Low", - "file": "python/imports/imports-function.py", - "line": 4, - "tool": "bandit" - }, - { - "category": "sast", - "message": "Consider possible security implications associated with pickle module.", - "cve": "python/imports/imports-function.py:dbda3cf4190279d30e0aad7dd137eca11272b0b225e8af4e8bf39682da67d956:B403", - "severity": "Low", - "confidence": "High", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/imports/imports-function.py", - "start_line": 2, - "end_line": 2 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B403", - "value": "B403" - } - ], - "priority": "Low", - "file": "python/imports/imports-function.py", - "line": 2, - "tool": "bandit" - }, - { - "category": "sast", - "message": "Consider possible security implications associated with Popen module.", - "cve": "python/imports/imports-from.py:eb8a0db9cd1a8c1ab39a77e6025021b1261cc2a0b026b2f4a11fca4e0636d8dd:B404", - "severity": "Low", - "confidence": "High", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/imports/imports-from.py", - "start_line": 7, - "end_line": 7 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B404", - "value": "B404" - } - ], - "priority": "Low", - "file": "python/imports/imports-from.py", - "line": 7, - "tool": "bandit" - }, - { - "category": "sast", - "message": "subprocess call with shell=True seems safe, but may be changed in the future, consider rewriting without shell", - "cve": "python/imports/imports-aliases.py:f99f9721e27537fbcb6699a4cf39c6740d6234d2c6f06cfc2d9ea977313c483d:B602", - "severity": "Low", - "confidence": "High", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/imports/imports-aliases.py", - "start_line": 9, - "end_line": 9 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B602", - "value": "B602", - "url": "https://docs.openstack.org/bandit/latest/plugins/b602_subprocess_popen_with_shell_equals_true.html" - } - ], - "priority": "Low", - "file": "python/imports/imports-aliases.py", - "line": 9, - "url": "https://docs.openstack.org/bandit/latest/plugins/b602_subprocess_popen_with_shell_equals_true.html", - "tool": "bandit" - }, - { - "category": "sast", - "message": "Consider possible security implications associated with subprocess module.", - "cve": "python/imports/imports-from.py:332a12ab1146698f614a905ce6a6a5401497a12281aef200e80522711c69dcf4:B404", - "severity": "Low", - "confidence": "High", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/imports/imports-from.py", - "start_line": 6, - "end_line": 6 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B404", - "value": "B404" - } - ], - "priority": "Low", - "file": "python/imports/imports-from.py", - "line": 6, - "tool": "bandit" - }, - { - "category": "sast", - "message": "Consider possible security implications associated with Popen module.", - "cve": "python/imports/imports-from.py:0a48de4a3d5348853a03666cb574697e3982998355e7a095a798bd02a5947276:B404", - "severity": "Low", - "confidence": "High", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/imports/imports-from.py", - "start_line": 1, - "end_line": 2 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B404", - "value": "B404" - } - ], - "priority": "Low", - "file": "python/imports/imports-from.py", - "line": 1, - "tool": "bandit" - }, - { - "category": "sast", - "message": "Consider possible security implications associated with pickle module.", - "cve": "python/imports/imports-aliases.py:51b71661dff994bde3529639a727a678c8f5c4c96f00d300913f6d5be1bbdf26:B403", - "severity": "Low", - "confidence": "High", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/imports/imports-aliases.py", - "start_line": 7, - "end_line": 8 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B403", - "value": "B403" - } - ], - "priority": "Low", - "file": "python/imports/imports-aliases.py", - "line": 7, - "tool": "bandit" - }, - { - "category": "sast", - "message": "Consider possible security implications associated with loads module.", - "cve": "python/imports/imports-aliases.py:6ff02aeb3149c01ab68484d794a94f58d5d3e3bb0d58557ef4153644ea68ea54:B403", - "severity": "Low", - "confidence": "High", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/imports/imports-aliases.py", - "start_line": 6, - "end_line": 6 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B403", - "value": "B403" - } - ], - "priority": "Low", - "file": "python/imports/imports-aliases.py", - "line": 6, - "tool": "bandit" - }, - { - "category": "sast", - "message": "Statically-sized arrays can be improperly restricted, leading to potential overflows or other issues (CWE-119!/CWE-120)", - "cve": "c/subdir/utils.c:b466873101951fe96e1332f6728eb7010acbbd5dfc3b65d7d53571d091a06d9e:CWE-119!/CWE-120", - "confidence": "Low", - "solution": "Perform bounds checking, use functions that limit length, or ensure that the size is larger than the maximum possible length", - "scanner": { - "id": "flawfinder", - "name": "Flawfinder" - }, - "location": { - "file": "c/subdir/utils.c", - "start_line": 4 - }, - "identifiers": [ - { - "type": "flawfinder_func_name", - "name": "Flawfinder - char", - "value": "char" - }, - { - "type": "cwe", - "name": "CWE-119", - "value": "119", - "url": "https://cwe.mitre.org/data/definitions/119.html" - }, - { - "type": "cwe", - "name": "CWE-120", - "value": "120", - "url": "https://cwe.mitre.org/data/definitions/120.html" - } - ], - "file": "c/subdir/utils.c", - "line": 4, - "url": "https://cwe.mitre.org/data/definitions/119.html", - "tool": "flawfinder" - }, - { - "category": "sast", - "message": "Check when opening files - can an attacker redirect it (via symlinks), force the opening of special file type (e.g., device files), move things around to create a race condition, control its ancestors, or change its contents? (CWE-362)", - "cve": "c/subdir/utils.c:bab681140fcc8fc3085b6bba74081b44ea145c1c98b5e70cf19ace2417d30770:CWE-362", - "confidence": "Low", - "scanner": { - "id": "flawfinder", - "name": "Flawfinder" - }, - "location": { - "file": "c/subdir/utils.c", - "start_line": 8 - }, - "identifiers": [ - { - "type": "flawfinder_func_name", - "name": "Flawfinder - fopen", - "value": "fopen" - }, - { - "type": "cwe", - "name": "CWE-362", - "value": "362", - "url": "https://cwe.mitre.org/data/definitions/362.html" - } - ], - "file": "c/subdir/utils.c", - "line": 8, - "url": "https://cwe.mitre.org/data/definitions/362.html", - "tool": "flawfinder" - }, - { - "category": "sast", - "message": "Statically-sized arrays can be improperly restricted, leading to potential overflows or other issues (CWE-119!/CWE-120)", - "cve": "cplusplus/src/hello.cpp:c8c6dd0afdae6814194cf0930b719f757ab7b379cf8f261e7f4f9f2f323a818a:CWE-119!/CWE-120", - "confidence": "Low", - "solution": "Perform bounds checking, use functions that limit length, or ensure that the size is larger than the maximum possible length", - "scanner": { - "id": "flawfinder", - "name": "Flawfinder" - }, - "location": { - "file": "cplusplus/src/hello.cpp", - "start_line": 6 - }, - "identifiers": [ - { - "type": "flawfinder_func_name", - "name": "Flawfinder - char", - "value": "char" - }, - { - "type": "cwe", - "name": "CWE-119", - "value": "119", - "url": "https://cwe.mitre.org/data/definitions/119.html" - }, - { - "type": "cwe", - "name": "CWE-120", - "value": "120", - "url": "https://cwe.mitre.org/data/definitions/120.html" - } - ], - "file": "cplusplus/src/hello.cpp", - "line": 6, - "url": "https://cwe.mitre.org/data/definitions/119.html", - "tool": "flawfinder" - }, - { - "category": "sast", - "message": "Does not check for buffer overflows when copying to destination [MS-banned] (CWE-120)", - "cve": "cplusplus/src/hello.cpp:331c04062c4fe0c7c486f66f59e82ad146ab33cdd76ae757ca41f392d568cbd0:CWE-120", - "confidence": "Low", - "solution": "Consider using snprintf, strcpy_s, or strlcpy (warning: strncpy easily misused)", - "scanner": { - "id": "flawfinder", - "name": "Flawfinder" - }, - "location": { - "file": "cplusplus/src/hello.cpp", - "start_line": 7 - }, - "identifiers": [ - { - "type": "flawfinder_func_name", - "name": "Flawfinder - strcpy", - "value": "strcpy" - }, - { - "type": "cwe", - "name": "CWE-120", - "value": "120", - "url": "https://cwe.mitre.org/data/definitions/120.html" - } - ], - "file": "cplusplus/src/hello.cpp", - "line": 7, - "url": "https://cwe.mitre.org/data/definitions/120.html", - "tool": "flawfinder" - } -] diff --git a/spec/fixtures/security-reports/feature-branch.zip b/spec/fixtures/security-reports/feature-branch.zip Binary files differdeleted file mode 100644 index dd49f4e9e1d..00000000000 --- a/spec/fixtures/security-reports/feature-branch.zip +++ /dev/null diff --git a/spec/fixtures/security-reports/feature-branch/gl-container-scanning-report.json b/spec/fixtures/security-reports/feature-branch/gl-container-scanning-report.json deleted file mode 100644 index 6f89d20d4bf..00000000000 --- a/spec/fixtures/security-reports/feature-branch/gl-container-scanning-report.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "image": "registry.gitlab.com/bikebilly/auto-devops-10-6/feature-branch:e7315ba964febb11bac8f5cd6ec433db8a3a1583", - "unapproved": ["CVE-2017-15650"], - "vulnerabilities": [ - { - "featurename": "musl", - "featureversion": "1.1.14-r15", - "vulnerability": "CVE-2017-15650", - "namespace": "alpine:v3.4", - "description": "", - "link": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-15650", - "severity": "Medium", - "fixedby": "1.1.14-r16" - } - ] -} diff --git a/spec/fixtures/security-reports/feature-branch/gl-dast-report.json b/spec/fixtures/security-reports/feature-branch/gl-dast-report.json deleted file mode 100644 index 3a308bf047e..00000000000 --- a/spec/fixtures/security-reports/feature-branch/gl-dast-report.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "site": { - "alerts": [ - { - "sourceid": "3", - "wascid": "15", - "cweid": "16", - "reference": "<p>http://msdn.microsoft.com/en-us/library/ie/gg622941%28v=vs.85%29.aspx</p><p>https://www.owasp.org/index.php/List_of_useful_HTTP_headers</p>", - "otherinfo": "<p>This issue still applies to error type pages (401, 403, 500, etc) as those pages are often still affected by injection issues, in which case there is still concern for browsers sniffing pages away from their actual content type.</p><p>At \"High\" threshold this scanner will not alert on client or server error responses.</p>", - "solution": "<p>Ensure that the application/web server sets the Content-Type header appropriately, and that it sets the X-Content-Type-Options header to 'nosniff' for all web pages.</p><p>If possible, ensure that the end user uses a standards-compliant and modern web browser that does not perform MIME-sniffing at all, or that can be directed by the web application/web server to not perform MIME-sniffing.</p>", - "count": "2", - "pluginid": "10021", - "alert": "X-Content-Type-Options Header Missing", - "name": "X-Content-Type-Options Header Missing", - "riskcode": "1", - "confidence": "2", - "riskdesc": "Low (Medium)", - "desc": "<p>The Anti-MIME-Sniffing header X-Content-Type-Options was not set to 'nosniff'. This allows older versions of Internet Explorer and Chrome to perform MIME-sniffing on the response body, potentially causing the response body to be interpreted and displayed as a content type other than the declared content type. Current (early 2014) and legacy versions of Firefox will use the declared content type (if one is set), rather than performing MIME-sniffing.</p>", - "instances": [ - { - "param": "X-Content-Type-Options", - "method": "GET", - "uri": "http://bikebilly-spring-auto-devops-review-feature-br-3y2gpb.35.192.176.43.xip.io" - }, - { - "param": "X-Content-Type-Options", - "method": "GET", - "uri": "http://bikebilly-spring-auto-devops-review-feature-br-3y2gpb.35.192.176.43.xip.io/" - } - ] - } - ], - "@ssl": "false", - "@port": "80", - "@host": "bikebilly-spring-auto-devops-review-feature-br-3y2gpb.35.192.176.43.xip.io", - "@name": "http://bikebilly-spring-auto-devops-review-feature-br-3y2gpb.35.192.176.43.xip.io" - }, - "@generated": "Fri, 13 Apr 2018 09:22:01", - "@version": "2.7.0" -} diff --git a/spec/fixtures/security-reports/feature-branch/gl-dependency-scanning-report.json b/spec/fixtures/security-reports/feature-branch/gl-dependency-scanning-report.json deleted file mode 100644 index 8555be6618c..00000000000 --- a/spec/fixtures/security-reports/feature-branch/gl-dependency-scanning-report.json +++ /dev/null @@ -1,181 +0,0 @@ -{ - "version": "1.3", - "vulnerabilities": [ - { - "category": "dependency_scanning", - "name": "io.netty/netty - CVE-2014-3488", - "message": "DoS by CPU exhaustion when using malicious SSL packets", - "cve": "app/pom.xml:io.netty/netty@3.9.1.Final:CVE-2014-3488", - "severity": "Unknown", - "solution": "Upgrade to the latest version", - "scanner": { - "id": "gemnasium", - "name": "Gemnasium" - }, - "location": { - "file": "app/pom.xml", - "dependency": { - "package": { - "name": "io.netty/netty" - }, - "version": "3.9.1.Final" - } - }, - "identifiers": [ - { - "type": "gemnasium", - "name": "Gemnasium-d1bf36d9-9f07-46cd-9cfc-8675338ada8f", - "value": "d1bf36d9-9f07-46cd-9cfc-8675338ada8f", - "url": "https://deps.sec.gitlab.com/packages/maven/io.netty/netty/versions/3.9.1.Final/advisories" - }, - { - "type": "cve", - "name": "CVE-2014-3488", - "value": "CVE-2014-3488", - "url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-3488" - } - ], - "links": [ - { - "url": "https://bugzilla.redhat.com/CVE-2014-3488" - }, - { - "url": "http://netty.io/news/2014/06/11/3.html" - }, - { - "url": "https://github.com/netty/netty/issues/2562" - } - ], - "priority": "Unknown", - "file": "app/pom.xml", - "url": "https://bugzilla.redhat.com/CVE-2014-3488", - "tool": "gemnasium" - }, - { - "category": "dependency_scanning", - "name": "Django - CVE-2017-12794", - "message": "Possible XSS in traceback section of technical 500 debug page", - "cve": "app/requirements.txt:Django@1.11.3:CVE-2017-12794", - "severity": "Unknown", - "solution": "Upgrade to latest version or apply patch.", - "scanner": { - "id": "gemnasium", - "name": "Gemnasium" - }, - "location": { - "file": "app/requirements.txt", - "dependency": { - "package": { - "name": "Django" - }, - "version": "1.11.3" - } - }, - "identifiers": [ - { - "type": "gemnasium", - "name": "Gemnasium-6162a015-8635-4a15-8d7c-dc9321db366f", - "value": "6162a015-8635-4a15-8d7c-dc9321db366f", - "url": "https://deps.sec.gitlab.com/packages/pypi/Django/versions/1.11.3/advisories" - }, - { - "type": "cve", - "name": "CVE-2017-12794", - "value": "CVE-2017-12794", - "url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-12794" - } - ], - "links": [ - { - "url": "https://www.djangoproject.com/weblog/2017/sep/05/security-releases/" - } - ], - "priority": "Unknown", - "file": "app/requirements.txt", - "url": "https://www.djangoproject.com/weblog/2017/sep/05/security-releases/", - "tool": "gemnasium" - }, - { - "category": "dependency_scanning", - "name": "nokogiri - USN-3424-1", - "message": "Vulnerabilities in libxml2", - "cve": "rails/Gemfile.lock:nokogiri@1.8.0:USN-3424-1", - "severity": "Unknown", - "solution": "Upgrade to latest version.", - "scanner": { - "id": "gemnasium", - "name": "Gemnasium" - }, - "location": { - "file": "rails/Gemfile.lock", - "dependency": { - "package": { - "name": "nokogiri" - }, - "version": "1.8.0" - } - }, - "identifiers": [ - { - "type": "gemnasium", - "name": "Gemnasium-06565b64-486d-4326-b906-890d9915804d", - "value": "06565b64-486d-4326-b906-890d9915804d", - "url": "https://deps.sec.gitlab.com/packages/gem/nokogiri/versions/1.8.0/advisories" - }, - { - "type": "usn", - "name": "USN-3424-1", - "value": "USN-3424-1", - "url": "https://usn.ubuntu.com/3424-1/" - } - ], - "links": [ - { - "url": "https://github.com/sparklemotion/nokogiri/issues/1673" - } - ], - "priority": "Unknown", - "file": "rails/Gemfile.lock", - "url": "https://github.com/sparklemotion/nokogiri/issues/1673", - "tool": "gemnasium" - }, - { - "category": "dependency_scanning", - "name": "ffi - CVE-2018-1000201", - "message": "ruby-ffi DDL loading issue on Windows OS", - "cve": "ffi:1.9.18:CVE-2018-1000201", - "severity": "High", - "solution": "upgrade to \u003e= 1.9.24", - "scanner": { - "id": "bundler_audit", - "name": "bundler-audit" - }, - "location": { - "file": "sast-sample-rails/Gemfile.lock", - "dependency": { - "package": { - "name": "ffi" - }, - "version": "1.9.18" - } - }, - "identifiers": [ - { - "type": "cve", - "name": "CVE-2018-1000201", - "value": "CVE-2018-1000201", - "url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-1000201" - } - ], - "links": [ - { - "url": "https://github.com/ffi/ffi/releases/tag/1.9.24" - } - ], - "priority": "High", - "file": "sast-sample-rails/Gemfile.lock", - "url": "https://github.com/ffi/ffi/releases/tag/1.9.24", - "tool": "bundler_audit" - } - ] -} diff --git a/spec/fixtures/security-reports/feature-branch/gl-license-management-report.json b/spec/fixtures/security-reports/feature-branch/gl-license-management-report.json deleted file mode 100644 index 5fd81fd69bd..00000000000 --- a/spec/fixtures/security-reports/feature-branch/gl-license-management-report.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "licenses": [ - { - "count": 1, - "name": "WTFPL" - }, - { - "count": 1, - "name": "MIT" - } - ], - "dependencies": [ - { - "license": { - "name": "MIT", - "url": "http://opensource.org/licenses/mit-license" - }, - "dependency": { - "name": "actioncable", - "url": "http://rubyonrails.org", - "description": "WebSocket framework for Rails.", - "pathes": [ - "." - ] - } - }, - { - "license": { - "name": "WTFPL", - "url": "http://www.wtfpl.net/" - }, - "dependency": { - "name": "wtfpl_init", - "url": "https://rubygems.org/gems/wtfpl_init", - "description": "Download WTFPL license file and rename to LICENSE.md or something", - "pathes": [ - "." - ] - } - } - ] -} diff --git a/spec/fixtures/security-reports/feature-branch/gl-sast-report.json b/spec/fixtures/security-reports/feature-branch/gl-sast-report.json deleted file mode 100644 index 4bef3d22f70..00000000000 --- a/spec/fixtures/security-reports/feature-branch/gl-sast-report.json +++ /dev/null @@ -1,947 +0,0 @@ -{ - "version": "1.2", - "vulnerabilities": [ - { - "category": "sast", - "message": "Probable insecure usage of temp file/directory.", - "cve": "python/hardcoded/hardcoded-tmp.py:52865813c884a507be1f152d654245af34aba8a391626d01f1ab6d3f52ec8779:B108", - "severity": "Medium", - "confidence": "Medium", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/hardcoded/hardcoded-tmp.py", - "start_line": 1, - "end_line": 1 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B108", - "value": "B108", - "url": "https://docs.openstack.org/bandit/latest/plugins/b108_hardcoded_tmp_directory.html" - } - ], - "priority": "Medium", - "file": "python/hardcoded/hardcoded-tmp.py", - "line": 1, - "url": "https://docs.openstack.org/bandit/latest/plugins/b108_hardcoded_tmp_directory.html", - "tool": "bandit" - }, - { - "category": "sast", - "name": "Predictable pseudorandom number generator", - "message": "Predictable pseudorandom number generator", - "cve": "groovy/src/main/java/com/gitlab/security_products/tests/App.groovy:47:PREDICTABLE_RANDOM", - "severity": "Medium", - "confidence": "Medium", - "scanner": { - "id": "find_sec_bugs", - "name": "Find Security Bugs" - }, - "location": { - "file": "groovy/src/main/java/com/gitlab/security_products/tests/App.groovy", - "start_line": 47, - "end_line": 47, - "class": "com.gitlab.security_products.tests.App", - "method": "generateSecretToken2" - }, - "identifiers": [ - { - "type": "find_sec_bugs_type", - "name": "Find Security Bugs-PREDICTABLE_RANDOM", - "value": "PREDICTABLE_RANDOM", - "url": "https://find-sec-bugs.github.io/bugs.htm#PREDICTABLE_RANDOM" - } - ], - "priority": "Medium", - "file": "groovy/src/main/java/com/gitlab/security_products/tests/App.groovy", - "line": 47, - "url": "https://find-sec-bugs.github.io/bugs.htm#PREDICTABLE_RANDOM", - "tool": "find_sec_bugs" - }, - { - "category": "sast", - "name": "Predictable pseudorandom number generator", - "message": "Predictable pseudorandom number generator", - "cve": "groovy/src/main/java/com/gitlab/security_products/tests/App.groovy:41:PREDICTABLE_RANDOM", - "severity": "Medium", - "confidence": "Medium", - "scanner": { - "id": "find_sec_bugs", - "name": "Find Security Bugs" - }, - "location": { - "file": "groovy/src/main/java/com/gitlab/security_products/tests/App.groovy", - "start_line": 41, - "end_line": 41, - "class": "com.gitlab.security_products.tests.App", - "method": "generateSecretToken1" - }, - "identifiers": [ - { - "type": "find_sec_bugs_type", - "name": "Find Security Bugs-PREDICTABLE_RANDOM", - "value": "PREDICTABLE_RANDOM", - "url": "https://find-sec-bugs.github.io/bugs.htm#PREDICTABLE_RANDOM" - } - ], - "priority": "Medium", - "file": "groovy/src/main/java/com/gitlab/security_products/tests/App.groovy", - "line": 41, - "url": "https://find-sec-bugs.github.io/bugs.htm#PREDICTABLE_RANDOM", - "tool": "find_sec_bugs" - }, - { - "category": "sast", - "message": "Use of insecure MD2, MD4, or MD5 hash function.", - "cve": "python/imports/imports-aliases.py:cb203b465dffb0cb3a8e8bd8910b84b93b0a5995a938e4b903dbb0cd6ffa1254:B303", - "severity": "Medium", - "confidence": "High", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/imports/imports-aliases.py", - "start_line": 11, - "end_line": 11 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B303", - "value": "B303" - } - ], - "priority": "Medium", - "file": "python/imports/imports-aliases.py", - "line": 11, - "tool": "bandit" - }, - { - "category": "sast", - "message": "Use of insecure MD2, MD4, or MD5 hash function.", - "cve": "python/imports/imports-aliases.py:a7173c43ae66bd07466632d819d450e0071e02dbf782763640d1092981f9631b:B303", - "severity": "Medium", - "confidence": "High", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/imports/imports-aliases.py", - "start_line": 12, - "end_line": 12 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B303", - "value": "B303" - } - ], - "priority": "Medium", - "file": "python/imports/imports-aliases.py", - "line": 12, - "tool": "bandit" - }, - { - "category": "sast", - "message": "Use of insecure MD2, MD4, or MD5 hash function.", - "cve": "python/imports/imports-aliases.py:017017b77deb0b8369b6065947833eeea752a92ec8a700db590fece3e934cf0d:B303", - "severity": "Medium", - "confidence": "High", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/imports/imports-aliases.py", - "start_line": 13, - "end_line": 13 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B303", - "value": "B303" - } - ], - "priority": "Medium", - "file": "python/imports/imports-aliases.py", - "line": 13, - "tool": "bandit" - }, - { - "category": "sast", - "message": "Use of insecure MD2, MD4, or MD5 hash function.", - "cve": "python/imports/imports-aliases.py:45fc8c53aea7b84f06bc4e590cc667678d6073c4c8a1d471177ca2146fb22db2:B303", - "severity": "Medium", - "confidence": "High", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/imports/imports-aliases.py", - "start_line": 14, - "end_line": 14 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B303", - "value": "B303" - } - ], - "priority": "Medium", - "file": "python/imports/imports-aliases.py", - "line": 14, - "tool": "bandit" - }, - { - "category": "sast", - "message": "Pickle library appears to be in use, possible security issue.", - "cve": "python/imports/imports-aliases.py:5f200d47291e7bbd8352db23019b85453ca048dd98ea0c291260fa7d009963a4:B301", - "severity": "Medium", - "confidence": "High", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/imports/imports-aliases.py", - "start_line": 15, - "end_line": 15 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B301", - "value": "B301" - } - ], - "priority": "Medium", - "file": "python/imports/imports-aliases.py", - "line": 15, - "tool": "bandit" - }, - { - "category": "sast", - "name": "ECB mode is insecure", - "message": "ECB mode is insecure", - "cve": "groovy/src/main/java/com/gitlab/security_products/tests/App.groovy:29:ECB_MODE", - "severity": "Medium", - "confidence": "High", - "scanner": { - "id": "find_sec_bugs", - "name": "Find Security Bugs" - }, - "location": { - "file": "groovy/src/main/java/com/gitlab/security_products/tests/App.groovy", - "start_line": 29, - "end_line": 29, - "class": "com.gitlab.security_products.tests.App", - "method": "insecureCypher" - }, - "identifiers": [ - { - "type": "find_sec_bugs_type", - "name": "Find Security Bugs-ECB_MODE", - "value": "ECB_MODE", - "url": "https://find-sec-bugs.github.io/bugs.htm#ECB_MODE" - } - ], - "priority": "Medium", - "file": "groovy/src/main/java/com/gitlab/security_products/tests/App.groovy", - "line": 29, - "url": "https://find-sec-bugs.github.io/bugs.htm#ECB_MODE", - "tool": "find_sec_bugs" - }, - { - "category": "sast", - "name": "Cipher with no integrity", - "message": "Cipher with no integrity", - "cve": "groovy/src/main/java/com/gitlab/security_products/tests/App.groovy:29:CIPHER_INTEGRITY", - "severity": "Medium", - "confidence": "High", - "scanner": { - "id": "find_sec_bugs", - "name": "Find Security Bugs" - }, - "location": { - "file": "groovy/src/main/java/com/gitlab/security_products/tests/App.groovy", - "start_line": 29, - "end_line": 29, - "class": "com.gitlab.security_products.tests.App", - "method": "insecureCypher" - }, - "identifiers": [ - { - "type": "find_sec_bugs_type", - "name": "Find Security Bugs-CIPHER_INTEGRITY", - "value": "CIPHER_INTEGRITY", - "url": "https://find-sec-bugs.github.io/bugs.htm#CIPHER_INTEGRITY" - } - ], - "priority": "Medium", - "file": "groovy/src/main/java/com/gitlab/security_products/tests/App.groovy", - "line": 29, - "url": "https://find-sec-bugs.github.io/bugs.htm#CIPHER_INTEGRITY", - "tool": "find_sec_bugs" - }, - { - "category": "sast", - "message": "Probable insecure usage of temp file/directory.", - "cve": "python/hardcoded/hardcoded-tmp.py:63dd4d626855555b816985d82c4614a790462a0a3ada89dc58eb97f9c50f3077:B108", - "severity": "Medium", - "confidence": "Medium", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/hardcoded/hardcoded-tmp.py", - "start_line": 14, - "end_line": 14 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B108", - "value": "B108", - "url": "https://docs.openstack.org/bandit/latest/plugins/b108_hardcoded_tmp_directory.html" - } - ], - "priority": "Medium", - "file": "python/hardcoded/hardcoded-tmp.py", - "line": 14, - "url": "https://docs.openstack.org/bandit/latest/plugins/b108_hardcoded_tmp_directory.html", - "tool": "bandit" - }, - { - "category": "sast", - "message": "Probable insecure usage of temp file/directory.", - "cve": "python/hardcoded/hardcoded-tmp.py:4ad6d4c40a8c263fc265f3384724014e0a4f8dd6200af83e51ff120420038031:B108", - "severity": "Medium", - "confidence": "Medium", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/hardcoded/hardcoded-tmp.py", - "start_line": 10, - "end_line": 10 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B108", - "value": "B108", - "url": "https://docs.openstack.org/bandit/latest/plugins/b108_hardcoded_tmp_directory.html" - } - ], - "priority": "Medium", - "file": "python/hardcoded/hardcoded-tmp.py", - "line": 10, - "url": "https://docs.openstack.org/bandit/latest/plugins/b108_hardcoded_tmp_directory.html", - "tool": "bandit" - }, - { - "category": "sast", - "message": "Consider possible security implications associated with Popen module.", - "cve": "python/imports/imports-aliases.py:2c3e1fa1e54c3c6646e8bcfaee2518153c6799b77587ff8d9a7b0631f6d34785:B404", - "severity": "Low", - "confidence": "High", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/imports/imports-aliases.py", - "start_line": 1, - "end_line": 1 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B404", - "value": "B404" - } - ], - "priority": "Low", - "file": "python/imports/imports-aliases.py", - "line": 1, - "tool": "bandit" - }, - { - "category": "sast", - "message": "Consider possible security implications associated with pickle module.", - "cve": "python/imports/imports.py:af58d07f6ad519ef5287fcae65bf1a6999448a1a3a8bc1ac2a11daa80d0b96bf:B403", - "severity": "Low", - "confidence": "High", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/imports/imports.py", - "start_line": 2, - "end_line": 2 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B403", - "value": "B403" - } - ], - "priority": "Low", - "file": "python/imports/imports.py", - "line": 2, - "tool": "bandit" - }, - { - "category": "sast", - "message": "Consider possible security implications associated with subprocess module.", - "cve": "python/imports/imports.py:8de9bc98029d212db530785a5f6780cfa663548746ff228ab8fa96c5bb82f089:B404", - "severity": "Low", - "confidence": "High", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/imports/imports.py", - "start_line": 4, - "end_line": 4 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B404", - "value": "B404" - } - ], - "priority": "Low", - "file": "python/imports/imports.py", - "line": 4, - "tool": "bandit" - }, - { - "category": "sast", - "message": "Possible hardcoded password: 'blerg'", - "cve": "python/hardcoded/hardcoded-passwords.py:97c30f1d76d2a88913e3ce9ae74087874d740f87de8af697a9c455f01119f633:B106", - "severity": "Low", - "confidence": "Medium", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/hardcoded/hardcoded-passwords.py", - "start_line": 22, - "end_line": 22 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B106", - "value": "B106", - "url": "https://docs.openstack.org/bandit/latest/plugins/b106_hardcoded_password_funcarg.html" - } - ], - "priority": "Low", - "file": "python/hardcoded/hardcoded-passwords.py", - "line": 22, - "url": "https://docs.openstack.org/bandit/latest/plugins/b106_hardcoded_password_funcarg.html", - "tool": "bandit" - }, - { - "category": "sast", - "message": "Possible hardcoded password: 'root'", - "cve": "python/hardcoded/hardcoded-passwords.py:7431c73a0bc16d94ece2a2e75ef38f302574d42c37ac0c3c38ad0b3bf8a59f10:B105", - "severity": "Low", - "confidence": "Medium", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/hardcoded/hardcoded-passwords.py", - "start_line": 5, - "end_line": 5 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B105", - "value": "B105", - "url": "https://docs.openstack.org/bandit/latest/plugins/b105_hardcoded_password_string.html" - } - ], - "priority": "Low", - "file": "python/hardcoded/hardcoded-passwords.py", - "line": 5, - "url": "https://docs.openstack.org/bandit/latest/plugins/b105_hardcoded_password_string.html", - "tool": "bandit" - }, - { - "category": "sast", - "message": "Possible hardcoded password: ''", - "cve": "python/hardcoded/hardcoded-passwords.py:d2d1857c27caedd49c57bfbcdc23afcc92bd66a22701fcdc632869aab4ca73ee:B105", - "severity": "Low", - "confidence": "Medium", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/hardcoded/hardcoded-passwords.py", - "start_line": 9, - "end_line": 9 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B105", - "value": "B105", - "url": "https://docs.openstack.org/bandit/latest/plugins/b105_hardcoded_password_string.html" - } - ], - "priority": "Low", - "file": "python/hardcoded/hardcoded-passwords.py", - "line": 9, - "url": "https://docs.openstack.org/bandit/latest/plugins/b105_hardcoded_password_string.html", - "tool": "bandit" - }, - { - "category": "sast", - "message": "Possible hardcoded password: 'ajklawejrkl42348swfgkg'", - "cve": "python/hardcoded/hardcoded-passwords.py:fb3866215a61393a5c9c32a3b60e2058171a23219c353f722cbd3567acab21d2:B105", - "severity": "Low", - "confidence": "Medium", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/hardcoded/hardcoded-passwords.py", - "start_line": 13, - "end_line": 13 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B105", - "value": "B105", - "url": "https://docs.openstack.org/bandit/latest/plugins/b105_hardcoded_password_string.html" - } - ], - "priority": "Low", - "file": "python/hardcoded/hardcoded-passwords.py", - "line": 13, - "url": "https://docs.openstack.org/bandit/latest/plugins/b105_hardcoded_password_string.html", - "tool": "bandit" - }, - { - "category": "sast", - "message": "Possible hardcoded password: 'blerg'", - "cve": "python/hardcoded/hardcoded-passwords.py:63c62a8b7e1e5224439bd26b28030585ac48741e28ca64561a6071080c560a5f:B105", - "severity": "Low", - "confidence": "Medium", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/hardcoded/hardcoded-passwords.py", - "start_line": 23, - "end_line": 23 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B105", - "value": "B105", - "url": "https://docs.openstack.org/bandit/latest/plugins/b105_hardcoded_password_string.html" - } - ], - "priority": "Low", - "file": "python/hardcoded/hardcoded-passwords.py", - "line": 23, - "url": "https://docs.openstack.org/bandit/latest/plugins/b105_hardcoded_password_string.html", - "tool": "bandit" - }, - { - "category": "sast", - "message": "Possible hardcoded password: 'blerg'", - "cve": "python/hardcoded/hardcoded-passwords.py:4311b06d08df8fa58229b341c531da8e1a31ec4520597bdff920cd5c098d86f9:B105", - "severity": "Low", - "confidence": "Medium", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/hardcoded/hardcoded-passwords.py", - "start_line": 24, - "end_line": 24 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B105", - "value": "B105", - "url": "https://docs.openstack.org/bandit/latest/plugins/b105_hardcoded_password_string.html" - } - ], - "priority": "Low", - "file": "python/hardcoded/hardcoded-passwords.py", - "line": 24, - "url": "https://docs.openstack.org/bandit/latest/plugins/b105_hardcoded_password_string.html", - "tool": "bandit" - }, - { - "category": "sast", - "message": "Consider possible security implications associated with subprocess module.", - "cve": "python/imports/imports-function.py:5858400c2f39047787702de44d03361ef8d954c9d14bd54ee1c2bef9e6a7df93:B404", - "severity": "Low", - "confidence": "High", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/imports/imports-function.py", - "start_line": 4, - "end_line": 4 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B404", - "value": "B404" - } - ], - "priority": "Low", - "file": "python/imports/imports-function.py", - "line": 4, - "tool": "bandit" - }, - { - "category": "sast", - "message": "Consider possible security implications associated with pickle module.", - "cve": "python/imports/imports-function.py:dbda3cf4190279d30e0aad7dd137eca11272b0b225e8af4e8bf39682da67d956:B403", - "severity": "Low", - "confidence": "High", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/imports/imports-function.py", - "start_line": 2, - "end_line": 2 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B403", - "value": "B403" - } - ], - "priority": "Low", - "file": "python/imports/imports-function.py", - "line": 2, - "tool": "bandit" - }, - { - "category": "sast", - "message": "Consider possible security implications associated with Popen module.", - "cve": "python/imports/imports-from.py:eb8a0db9cd1a8c1ab39a77e6025021b1261cc2a0b026b2f4a11fca4e0636d8dd:B404", - "severity": "Low", - "confidence": "High", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/imports/imports-from.py", - "start_line": 7, - "end_line": 7 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B404", - "value": "B404" - } - ], - "priority": "Low", - "file": "python/imports/imports-from.py", - "line": 7, - "tool": "bandit" - }, - { - "category": "sast", - "message": "subprocess call with shell=True seems safe, but may be changed in the future, consider rewriting without shell", - "cve": "python/imports/imports-aliases.py:f99f9721e27537fbcb6699a4cf39c6740d6234d2c6f06cfc2d9ea977313c483d:B602", - "severity": "Low", - "confidence": "High", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/imports/imports-aliases.py", - "start_line": 9, - "end_line": 9 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B602", - "value": "B602", - "url": "https://docs.openstack.org/bandit/latest/plugins/b602_subprocess_popen_with_shell_equals_true.html" - } - ], - "priority": "Low", - "file": "python/imports/imports-aliases.py", - "line": 9, - "url": "https://docs.openstack.org/bandit/latest/plugins/b602_subprocess_popen_with_shell_equals_true.html", - "tool": "bandit" - }, - { - "category": "sast", - "message": "Consider possible security implications associated with subprocess module.", - "cve": "python/imports/imports-from.py:332a12ab1146698f614a905ce6a6a5401497a12281aef200e80522711c69dcf4:B404", - "severity": "Low", - "confidence": "High", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/imports/imports-from.py", - "start_line": 6, - "end_line": 6 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B404", - "value": "B404" - } - ], - "priority": "Low", - "file": "python/imports/imports-from.py", - "line": 6, - "tool": "bandit" - }, - { - "category": "sast", - "message": "Consider possible security implications associated with Popen module.", - "cve": "python/imports/imports-from.py:0a48de4a3d5348853a03666cb574697e3982998355e7a095a798bd02a5947276:B404", - "severity": "Low", - "confidence": "High", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/imports/imports-from.py", - "start_line": 1, - "end_line": 2 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B404", - "value": "B404" - } - ], - "priority": "Low", - "file": "python/imports/imports-from.py", - "line": 1, - "tool": "bandit" - }, - { - "category": "sast", - "message": "Consider possible security implications associated with pickle module.", - "cve": "python/imports/imports-aliases.py:51b71661dff994bde3529639a727a678c8f5c4c96f00d300913f6d5be1bbdf26:B403", - "severity": "Low", - "confidence": "High", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/imports/imports-aliases.py", - "start_line": 7, - "end_line": 8 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B403", - "value": "B403" - } - ], - "priority": "Low", - "file": "python/imports/imports-aliases.py", - "line": 7, - "tool": "bandit" - }, - { - "category": "sast", - "message": "Consider possible security implications associated with loads module.", - "cve": "python/imports/imports-aliases.py:6ff02aeb3149c01ab68484d794a94f58d5d3e3bb0d58557ef4153644ea68ea54:B403", - "severity": "Low", - "confidence": "High", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/imports/imports-aliases.py", - "start_line": 6, - "end_line": 6 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B403", - "value": "B403" - } - ], - "priority": "Low", - "file": "python/imports/imports-aliases.py", - "line": 6, - "tool": "bandit" - }, - { - "category": "sast", - "message": "Statically-sized arrays can be improperly restricted, leading to potential overflows or other issues (CWE-119!/CWE-120)", - "cve": "c/subdir/utils.c:b466873101951fe96e1332f6728eb7010acbbd5dfc3b65d7d53571d091a06d9e:CWE-119!/CWE-120", - "confidence": "Low", - "solution": "Perform bounds checking, use functions that limit length, or ensure that the size is larger than the maximum possible length", - "scanner": { - "id": "flawfinder", - "name": "Flawfinder" - }, - "location": { - "file": "c/subdir/utils.c", - "start_line": 4 - }, - "identifiers": [ - { - "type": "cwe", - "name": "CWE-119", - "value": "119", - "url": "https://cwe.mitre.org/data/definitions/119.html" - }, - { - "type": "cwe", - "name": "CWE-120", - "value": "120", - "url": "https://cwe.mitre.org/data/definitions/120.html" - } - ], - "file": "c/subdir/utils.c", - "line": 4, - "url": "https://cwe.mitre.org/data/definitions/119.html", - "tool": "flawfinder" - }, - { - "category": "sast", - "message": "Check when opening files - can an attacker redirect it (via symlinks), force the opening of special file type (e.g., device files), move things around to create a race condition, control its ancestors, or change its contents? (CWE-362)", - "cve": "c/subdir/utils.c:bab681140fcc8fc3085b6bba74081b44ea145c1c98b5e70cf19ace2417d30770:CWE-362", - "confidence": "Low", - "scanner": { - "id": "flawfinder", - "name": "Flawfinder" - }, - "location": { - "file": "c/subdir/utils.c", - "start_line": 8 - }, - "identifiers": [ - { - "type": "cwe", - "name": "CWE-362", - "value": "362", - "url": "https://cwe.mitre.org/data/definitions/362.html" - } - ], - "file": "c/subdir/utils.c", - "line": 8, - "url": "https://cwe.mitre.org/data/definitions/362.html", - "tool": "flawfinder" - }, - { - "category": "sast", - "message": "Statically-sized arrays can be improperly restricted, leading to potential overflows or other issues (CWE-119!/CWE-120)", - "cve": "cplusplus/src/hello.cpp:c8c6dd0afdae6814194cf0930b719f757ab7b379cf8f261e7f4f9f2f323a818a:CWE-119!/CWE-120", - "confidence": "Low", - "solution": "Perform bounds checking, use functions that limit length, or ensure that the size is larger than the maximum possible length", - "scanner": { - "id": "flawfinder", - "name": "Flawfinder" - }, - "location": { - "file": "cplusplus/src/hello.cpp", - "start_line": 6 - }, - "identifiers": [ - { - "type": "cwe", - "name": "CWE-119", - "value": "119", - "url": "https://cwe.mitre.org/data/definitions/119.html" - }, - { - "type": "cwe", - "name": "CWE-120", - "value": "120", - "url": "https://cwe.mitre.org/data/definitions/120.html" - } - ], - "file": "cplusplus/src/hello.cpp", - "line": 6, - "url": "https://cwe.mitre.org/data/definitions/119.html", - "tool": "flawfinder" - }, - { - "category": "sast", - "message": "Does not check for buffer overflows when copying to destination [MS-banned] (CWE-120)", - "cve": "cplusplus/src/hello.cpp:331c04062c4fe0c7c486f66f59e82ad146ab33cdd76ae757ca41f392d568cbd0:CWE-120", - "confidence": "Low", - "solution": "Consider using snprintf, strcpy_s, or strlcpy (warning: strncpy easily misused)", - "scanner": { - "id": "flawfinder", - "name": "Flawfinder" - }, - "location": { - "file": "cplusplus/src/hello.cpp", - "start_line": 7 - }, - "identifiers": [ - { - "type": "cwe", - "name": "CWE-120", - "value": "120", - "url": "https://cwe.mitre.org/data/definitions/120.html" - } - ], - "file": "cplusplus/src/hello.cpp", - "line": 7, - "url": "https://cwe.mitre.org/data/definitions/120.html", - "tool": "flawfinder" - } - ] -} diff --git a/spec/fixtures/security-reports/master.zip b/spec/fixtures/security-reports/master.zip Binary files differdeleted file mode 100644 index 2261b5a1674..00000000000 --- a/spec/fixtures/security-reports/master.zip +++ /dev/null diff --git a/spec/fixtures/security-reports/master/gl-container-scanning-report.json b/spec/fixtures/security-reports/master/gl-container-scanning-report.json deleted file mode 100644 index 03dfc647162..00000000000 --- a/spec/fixtures/security-reports/master/gl-container-scanning-report.json +++ /dev/null @@ -1,105 +0,0 @@ -{ - "image": "registry.gitlab.com/groulot/container-scanning-test/master:5f21de6956aee99ddb68ae49498662d9872f50ff", - "unapproved": [ - "CVE-2017-18269", - "CVE-2017-16997", - "CVE-2018-1000001", - "CVE-2016-10228", - "CVE-2018-18520", - "CVE-2010-4052", - "CVE-2018-16869", - "CVE-2018-18311" - ], - "vulnerabilities": [ - { - "featurename": "glibc", - "featureversion": "2.24-11+deb9u3", - "vulnerability": "CVE-2017-18269", - "namespace": "debian:9", - "description": "SSE2-optimized memmove implementation problem.", - "link": "https://security-tracker.debian.org/tracker/CVE-2017-18269", - "severity": "Defcon1", - "fixedby": "2.24-11+deb9u4" - }, - { - "featurename": "glibc", - "featureversion": "2.24-11+deb9u3", - "vulnerability": "CVE-2017-16997", - "namespace": "debian:9", - "description": "elf/dl-load.c in the GNU C Library (aka glibc or libc6) 2.19 through 2.26 mishandles RPATH and RUNPATH containing $ORIGIN for a privileged (setuid or AT_SECURE) program, which allows local users to gain privileges via a Trojan horse library in the current working directory, related to the fillin_rpath and decompose_rpath functions. This is associated with misinterpretion of an empty RPATH/RUNPATH token as the \"./\" directory. NOTE: this configuration of RPATH/RUNPATH for a privileged program is apparently very uncommon; most likely, no such program is shipped with any common Linux distribution.", - "link": "https://security-tracker.debian.org/tracker/CVE-2017-16997", - "severity": "Critical", - "fixedby": "" - }, - { - "featurename": "glibc", - "featureversion": "2.24-11+deb9u3", - "vulnerability": "CVE-2018-1000001", - "namespace": "debian:9", - "description": "In glibc 2.26 and earlier there is confusion in the usage of getcwd() by realpath() which can be used to write before the destination buffer leading to a buffer underflow and potential code execution.", - "link": "https://security-tracker.debian.org/tracker/CVE-2018-1000001", - "severity": "High", - "fixedby": "" - }, - { - "featurename": "glibc", - "featureversion": "2.24-11+deb9u3", - "vulnerability": "CVE-2016-10228", - "namespace": "debian:9", - "description": "The iconv program in the GNU C Library (aka glibc or libc6) 2.25 and earlier, when invoked with the -c option, enters an infinite loop when processing invalid multi-byte input sequences, leading to a denial of service.", - "link": "https://security-tracker.debian.org/tracker/CVE-2016-10228", - "severity": "Medium", - "fixedby": "" - }, - { - "featurename": "elfutils", - "featureversion": "0.168-1", - "vulnerability": "CVE-2018-18520", - "namespace": "debian:9", - "description": "An Invalid Memory Address Dereference exists in the function elf_end in libelf in elfutils through v0.174. Although eu-size is intended to support ar files inside ar files, handle_ar in size.c closes the outer ar file before handling all inner entries. The vulnerability allows attackers to cause a denial of service (application crash) with a crafted ELF file.", - "link": "https://security-tracker.debian.org/tracker/CVE-2018-18520", - "severity": "Low", - "fixedby": "" - }, - { - "featurename": "glibc", - "featureversion": "2.24-11+deb9u3", - "vulnerability": "CVE-2010-4052", - "namespace": "debian:9", - "description": "Stack consumption vulnerability in the regcomp implementation in the GNU C Library (aka glibc or libc6) through 2.11.3, and 2.12.x through 2.12.2, allows context-dependent attackers to cause a denial of service (resource exhaustion) via a regular expression containing adjacent repetition operators, as demonstrated by a {10,}{10,}{10,}{10,} sequence in the proftpd.gnu.c exploit for ProFTPD.", - "link": "https://security-tracker.debian.org/tracker/CVE-2010-4052", - "severity": "Negligible", - "fixedby": "" - }, - { - "featurename": "nettle", - "featureversion": "3.3-1", - "vulnerability": "CVE-2018-16869", - "namespace": "debian:9", - "description": "A Bleichenbacher type side-channel based padding oracle attack was found in the way nettle handles endian conversion of RSA decrypted PKCS#1 v1.5 data. An attacker who is able to run a process on the same physical core as the victim process, could use this flaw extract plaintext or in some cases downgrade any TLS connections to a vulnerable server.", - "link": "https://security-tracker.debian.org/tracker/CVE-2018-16869", - "severity": "Unknown", - "fixedby": "" - }, - { - "featurename": "perl", - "featureversion": "5.24.1-3+deb9u4", - "vulnerability": "CVE-2018-18311", - "namespace": "debian:9", - "description": "Perl before 5.26.3 and 5.28.x before 5.28.1 has a buffer overflow via a crafted regular expression that triggers invalid write operations.", - "link": "https://security-tracker.debian.org/tracker/CVE-2018-18311", - "severity": "Unknown", - "fixedby": "5.24.1-3+deb9u5" - }, - { - "featurename": "foo", - "featureversion": "1.3", - "vulnerability": "CVE-2018-666", - "namespace": "debian:9", - "description": "Foo has a vulnerability nobody cares about and whitelist.", - "link": "https://security-tracker.debian.org/tracker/CVE-2018-666", - "severity": "Unknown", - "fixedby": "1.4" - } - ] -} diff --git a/spec/fixtures/security-reports/master/gl-dast-report.json b/spec/fixtures/security-reports/master/gl-dast-report.json deleted file mode 100644 index df459d9419d..00000000000 --- a/spec/fixtures/security-reports/master/gl-dast-report.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "site": [ - { - "alerts": [ - { - "sourceid": "3", - "wascid": "15", - "cweid": "16", - "reference": "<p>http://msdn.microsoft.com/en-us/library/ie/gg622941%28v=vs.85%29.aspx</p><p>https://www.owasp.org/index.php/List_of_useful_HTTP_headers</p>", - "otherinfo": "<p>This issue still applies to error type pages (401, 403, 500, etc) as those pages are often still affected by injection issues, in which case there is still concern for browsers sniffing pages away from their actual content type.</p><p>At \"High\" threshold this scanner will not alert on client or server error responses.</p>", - "solution": "<p>Ensure that the application/web server sets the Content-Type header appropriately, and that it sets the X-Content-Type-Options header to 'nosniff' for all web pages.</p><p>If possible, ensure that the end user uses a standards-compliant and modern web browser that does not perform MIME-sniffing at all, or that can be directed by the web application/web server to not perform MIME-sniffing.</p>", - "count": "2", - "pluginid": "10021", - "alert": "X-Content-Type-Options Header Missing", - "name": "X-Content-Type-Options Header Missing", - "riskcode": "1", - "confidence": "2", - "riskdesc": "Low (Medium)", - "desc": "<p>The Anti-MIME-Sniffing header X-Content-Type-Options was not set to 'nosniff'. This allows older versions of Internet Explorer and Chrome to perform MIME-sniffing on the response body, potentially causing the response body to be interpreted and displayed as a content type other than the declared content type. Current (early 2014) and legacy versions of Firefox will use the declared content type (if one is set), rather than performing MIME-sniffing.</p>", - "instances": [ - { - "param": "X-Content-Type-Options", - "method": "GET", - "uri": "http://bikebilly-spring-auto-devops-review-feature-br-3y2gpb.35.192.176.43.xip.io" - }, - { - "param": "X-Content-Type-Options", - "method": "GET", - "uri": "http://bikebilly-spring-auto-devops-review-feature-br-3y2gpb.35.192.176.43.xip.io/" - } - ] - } - ], - "@ssl": "false", - "@port": "80", - "@host": "bikebilly-spring-auto-devops-review-feature-br-3y2gpb.35.192.176.43.xip.io", - "@name": "http://bikebilly-spring-auto-devops-review-feature-br-3y2gpb.35.192.176.43.xip.io" - } - ], - "@generated": "Fri, 13 Apr 2018 09:22:01", - "@version": "2.7.0" -} diff --git a/spec/fixtures/security-reports/master/gl-dependency-scanning-report.json b/spec/fixtures/security-reports/master/gl-dependency-scanning-report.json deleted file mode 100644 index 8555be6618c..00000000000 --- a/spec/fixtures/security-reports/master/gl-dependency-scanning-report.json +++ /dev/null @@ -1,181 +0,0 @@ -{ - "version": "1.3", - "vulnerabilities": [ - { - "category": "dependency_scanning", - "name": "io.netty/netty - CVE-2014-3488", - "message": "DoS by CPU exhaustion when using malicious SSL packets", - "cve": "app/pom.xml:io.netty/netty@3.9.1.Final:CVE-2014-3488", - "severity": "Unknown", - "solution": "Upgrade to the latest version", - "scanner": { - "id": "gemnasium", - "name": "Gemnasium" - }, - "location": { - "file": "app/pom.xml", - "dependency": { - "package": { - "name": "io.netty/netty" - }, - "version": "3.9.1.Final" - } - }, - "identifiers": [ - { - "type": "gemnasium", - "name": "Gemnasium-d1bf36d9-9f07-46cd-9cfc-8675338ada8f", - "value": "d1bf36d9-9f07-46cd-9cfc-8675338ada8f", - "url": "https://deps.sec.gitlab.com/packages/maven/io.netty/netty/versions/3.9.1.Final/advisories" - }, - { - "type": "cve", - "name": "CVE-2014-3488", - "value": "CVE-2014-3488", - "url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-3488" - } - ], - "links": [ - { - "url": "https://bugzilla.redhat.com/CVE-2014-3488" - }, - { - "url": "http://netty.io/news/2014/06/11/3.html" - }, - { - "url": "https://github.com/netty/netty/issues/2562" - } - ], - "priority": "Unknown", - "file": "app/pom.xml", - "url": "https://bugzilla.redhat.com/CVE-2014-3488", - "tool": "gemnasium" - }, - { - "category": "dependency_scanning", - "name": "Django - CVE-2017-12794", - "message": "Possible XSS in traceback section of technical 500 debug page", - "cve": "app/requirements.txt:Django@1.11.3:CVE-2017-12794", - "severity": "Unknown", - "solution": "Upgrade to latest version or apply patch.", - "scanner": { - "id": "gemnasium", - "name": "Gemnasium" - }, - "location": { - "file": "app/requirements.txt", - "dependency": { - "package": { - "name": "Django" - }, - "version": "1.11.3" - } - }, - "identifiers": [ - { - "type": "gemnasium", - "name": "Gemnasium-6162a015-8635-4a15-8d7c-dc9321db366f", - "value": "6162a015-8635-4a15-8d7c-dc9321db366f", - "url": "https://deps.sec.gitlab.com/packages/pypi/Django/versions/1.11.3/advisories" - }, - { - "type": "cve", - "name": "CVE-2017-12794", - "value": "CVE-2017-12794", - "url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-12794" - } - ], - "links": [ - { - "url": "https://www.djangoproject.com/weblog/2017/sep/05/security-releases/" - } - ], - "priority": "Unknown", - "file": "app/requirements.txt", - "url": "https://www.djangoproject.com/weblog/2017/sep/05/security-releases/", - "tool": "gemnasium" - }, - { - "category": "dependency_scanning", - "name": "nokogiri - USN-3424-1", - "message": "Vulnerabilities in libxml2", - "cve": "rails/Gemfile.lock:nokogiri@1.8.0:USN-3424-1", - "severity": "Unknown", - "solution": "Upgrade to latest version.", - "scanner": { - "id": "gemnasium", - "name": "Gemnasium" - }, - "location": { - "file": "rails/Gemfile.lock", - "dependency": { - "package": { - "name": "nokogiri" - }, - "version": "1.8.0" - } - }, - "identifiers": [ - { - "type": "gemnasium", - "name": "Gemnasium-06565b64-486d-4326-b906-890d9915804d", - "value": "06565b64-486d-4326-b906-890d9915804d", - "url": "https://deps.sec.gitlab.com/packages/gem/nokogiri/versions/1.8.0/advisories" - }, - { - "type": "usn", - "name": "USN-3424-1", - "value": "USN-3424-1", - "url": "https://usn.ubuntu.com/3424-1/" - } - ], - "links": [ - { - "url": "https://github.com/sparklemotion/nokogiri/issues/1673" - } - ], - "priority": "Unknown", - "file": "rails/Gemfile.lock", - "url": "https://github.com/sparklemotion/nokogiri/issues/1673", - "tool": "gemnasium" - }, - { - "category": "dependency_scanning", - "name": "ffi - CVE-2018-1000201", - "message": "ruby-ffi DDL loading issue on Windows OS", - "cve": "ffi:1.9.18:CVE-2018-1000201", - "severity": "High", - "solution": "upgrade to \u003e= 1.9.24", - "scanner": { - "id": "bundler_audit", - "name": "bundler-audit" - }, - "location": { - "file": "sast-sample-rails/Gemfile.lock", - "dependency": { - "package": { - "name": "ffi" - }, - "version": "1.9.18" - } - }, - "identifiers": [ - { - "type": "cve", - "name": "CVE-2018-1000201", - "value": "CVE-2018-1000201", - "url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-1000201" - } - ], - "links": [ - { - "url": "https://github.com/ffi/ffi/releases/tag/1.9.24" - } - ], - "priority": "High", - "file": "sast-sample-rails/Gemfile.lock", - "url": "https://github.com/ffi/ffi/releases/tag/1.9.24", - "tool": "bundler_audit" - } - ] -} diff --git a/spec/fixtures/security-reports/master/gl-license-management-report.json b/spec/fixtures/security-reports/master/gl-license-management-report.json deleted file mode 100644 index e0de6f58fdf..00000000000 --- a/spec/fixtures/security-reports/master/gl-license-management-report.json +++ /dev/null @@ -1,817 +0,0 @@ -{ - "licenses": [ - { - "count": 52, - "name": "MIT" - }, - { - "count": 3, - "name": "New BSD" - }, - { - "count": 1, - "name": "Apache 2.0" - }, - { - "count": 1, - "name": "unknown" - } - ], - "dependencies": [ - { - "license": { - "name": "MIT", - "url": "http://opensource.org/licenses/mit-license" - }, - "dependency": { - "name": "actioncable", - "url": "http://rubyonrails.org", - "description": "WebSocket framework for Rails.", - "pathes": [ - "." - ] - } - }, - { - "license": { - "name": "MIT", - "url": "http://opensource.org/licenses/mit-license" - }, - "dependency": { - "name": "actionmailer", - "url": "http://rubyonrails.org", - "description": "Email composition, delivery, and receiving framework (part of Rails).", - "pathes": [ - "." - ] - } - }, - { - "license": { - "name": "MIT", - "url": "http://opensource.org/licenses/mit-license" - }, - "dependency": { - "name": "actionpack", - "url": "http://rubyonrails.org", - "description": "Web-flow and rendering framework putting the VC in MVC (part of Rails).", - "pathes": [ - "." - ] - } - }, - { - "license": { - "name": "MIT", - "url": "http://opensource.org/licenses/mit-license" - }, - "dependency": { - "name": "actionview", - "url": "http://rubyonrails.org", - "description": "Rendering framework putting the V in MVC (part of Rails).", - "pathes": [ - "." - ] - } - }, - { - "license": { - "name": "MIT", - "url": "http://opensource.org/licenses/mit-license" - }, - "dependency": { - "name": "activejob", - "url": "http://rubyonrails.org", - "description": "Job framework with pluggable queues.", - "pathes": [ - "." - ] - } - }, - { - "license": { - "name": "MIT", - "url": "http://opensource.org/licenses/mit-license" - }, - "dependency": { - "name": "activemodel", - "url": "http://rubyonrails.org", - "description": "A toolkit for building modeling frameworks (part of Rails).", - "pathes": [ - "." - ] - } - }, - { - "license": { - "name": "MIT", - "url": "http://opensource.org/licenses/mit-license" - }, - "dependency": { - "name": "activerecord", - "url": "http://rubyonrails.org", - "description": "Object-relational mapper framework (part of Rails).", - "pathes": [ - "." - ] - } - }, - { - "license": { - "name": "MIT", - "url": "http://opensource.org/licenses/mit-license" - }, - "dependency": { - "name": "activesupport", - "url": "http://rubyonrails.org", - "description": "A toolkit of support libraries and Ruby core extensions extracted from the Rails framework.", - "pathes": [ - "." - ] - } - }, - { - "license": { - "name": "MIT", - "url": "http://opensource.org/licenses/mit-license" - }, - "dependency": { - "name": "arel", - "url": "https://github.com/rails/arel", - "description": "Arel Really Exasperates Logicians Arel is a SQL AST manager for Ruby", - "pathes": [ - "." - ] - } - }, - { - "license": { - "name": "MIT", - "url": "http://opensource.org/licenses/mit-license" - }, - "dependency": { - "name": "builder", - "url": "http://onestepback.org", - "description": "Builders for MarkUp.", - "pathes": [ - "." - ] - } - }, - { - "license": { - "name": "MIT", - "url": "http://opensource.org/licenses/mit-license" - }, - "dependency": { - "name": "bundler", - "url": "http://bundler.io", - "description": "The best way to manage your application's dependencies", - "pathes": [ - "." - ] - } - }, - { - "license": { - "name": "MIT", - "url": "http://opensource.org/licenses/mit-license" - }, - "dependency": { - "name": "coffee-rails", - "url": "https://github.com/rails/coffee-rails", - "description": "CoffeeScript adapter for the Rails asset pipeline.", - "pathes": [ - "." - ] - } - }, - { - "license": { - "name": "MIT", - "url": "http://opensource.org/licenses/mit-license" - }, - "dependency": { - "name": "coffee-script", - "url": "http://github.com/josh/ruby-coffee-script", - "description": "Ruby CoffeeScript Compiler", - "pathes": [ - "." - ] - } - }, - { - "license": { - "name": "MIT", - "url": "http://opensource.org/licenses/mit-license" - }, - "dependency": { - "name": "coffee-script-source", - "url": "http://coffeescript.org", - "description": "The CoffeeScript Compiler", - "pathes": [ - "." - ] - } - }, - { - "license": { - "name": "MIT", - "url": "http://opensource.org/licenses/mit-license" - }, - "dependency": { - "name": "concurrent-ruby", - "url": "http://www.concurrent-ruby.com", - "description": "Modern concurrency tools for Ruby. Inspired by Erlang, Clojure, Scala, Haskell, F#, C#, Java, and classic concurrency patterns.", - "pathes": [ - "." - ] - } - }, - { - "license": { - "name": "MIT", - "url": "http://opensource.org/licenses/mit-license" - }, - "dependency": { - "name": "crass", - "url": "https://github.com/rgrove/crass/", - "description": "CSS parser based on the CSS Syntax Level 3 spec.", - "pathes": [ - "." - ] - } - }, - { - "license": { - "name": "MIT", - "url": "http://opensource.org/licenses/mit-license" - }, - "dependency": { - "name": "erubis", - "url": "http://www.kuwata-lab.com/erubis/", - "description": "a fast and extensible eRuby implementation which supports multi-language", - "pathes": [ - "." - ] - } - }, - { - "license": { - "name": "MIT", - "url": "http://opensource.org/licenses/mit-license" - }, - "dependency": { - "name": "execjs", - "url": "https://github.com/rails/execjs", - "description": "Run JavaScript code from Ruby", - "pathes": [ - "." - ] - } - }, - { - "license": { - "name": "New BSD", - "url": "http://opensource.org/licenses/BSD-3-Clause" - }, - "dependency": { - "name": "ffi", - "url": "http://wiki.github.com/ffi/ffi", - "description": "Ruby FFI", - "pathes": [ - "." - ] - } - }, - { - "license": { - "name": "MIT", - "url": "http://opensource.org/licenses/mit-license" - }, - "dependency": { - "name": "globalid", - "url": "http://www.rubyonrails.org", - "description": "Refer to any model with a URI: gid://app/class/id", - "pathes": [ - "." - ] - } - }, - { - "license": { - "name": "MIT", - "url": "http://opensource.org/licenses/mit-license" - }, - "dependency": { - "name": "i18n", - "url": "http://github.com/svenfuchs/i18n", - "description": "New wave Internationalization support for Ruby", - "pathes": [ - "." - ] - } - }, - { - "license": { - "name": "MIT", - "url": "http://opensource.org/licenses/mit-license" - }, - "dependency": { - "name": "jbuilder", - "url": "https://github.com/rails/jbuilder", - "description": "Create JSON structures via a Builder-style DSL", - "pathes": [ - "." - ] - } - }, - { - "license": { - "name": "MIT", - "url": "http://opensource.org/licenses/mit-license" - }, - "dependency": { - "name": "loofah", - "description": "", - "pathes": [ - "." - ] - } - }, - { - "license": { - "name": "MIT", - "url": "http://opensource.org/licenses/mit-license" - }, - "dependency": { - "name": "mail", - "url": "https://github.com/mikel/mail", - "description": "Mail provides a nice Ruby DSL for making, sending and reading emails.", - "pathes": [ - "." - ] - } - }, - { - "license": { - "name": "MIT", - "url": "http://opensource.org/licenses/mit-license" - }, - "dependency": { - "name": "method_source", - "url": "http://banisterfiend.wordpress.com", - "description": "retrieve the sourcecode for a method", - "pathes": [ - "." - ] - } - }, - { - "license": { - "name": "MIT", - "url": "http://opensource.org/licenses/mit-license" - }, - "dependency": { - "name": "mini_mime", - "url": "https://github.com/discourse/mini_mime", - "description": "A lightweight mime type lookup toy", - "pathes": [ - "." - ] - } - }, - { - "license": { - "name": "MIT", - "url": "http://opensource.org/licenses/mit-license" - }, - "dependency": { - "name": "mini_portile2", - "url": "http://github.com/flavorjones/mini_portile", - "description": "Simplistic port-like solution for developers", - "pathes": [ - "." - ] - } - }, - { - "license": { - "name": "MIT", - "url": "http://opensource.org/licenses/mit-license" - }, - "dependency": { - "name": "minitest", - "url": "https://github.com/seattlerb/minitest", - "description": "minitest provides a complete suite of testing facilities supporting TDD, BDD, mocking, and benchmarking", - "pathes": [ - "." - ] - } - }, - { - "license": { - "name": "MIT", - "url": "http://opensource.org/licenses/mit-license" - }, - "dependency": { - "name": "multi_json", - "url": "http://github.com/intridea/multi_json", - "description": "A common interface to multiple JSON libraries.", - "pathes": [ - "." - ] - } - }, - { - "license": { - "name": "MIT", - "url": "http://opensource.org/licenses/mit-license" - }, - "dependency": { - "name": "nio4r", - "url": "https://github.com/celluloid/nio4r", - "description": "NIO provides a high performance selector API for monitoring IO objects", - "pathes": [ - "." - ] - } - }, - { - "license": { - "name": "MIT", - "url": "http://opensource.org/licenses/mit-license" - }, - "dependency": { - "name": "nokogiri", - "url": "http://nokogiri.org", - "description": "Nokogiri (鋸) is an HTML, XML, SAX, and Reader parser", - "pathes": [ - "." - ] - } - }, - { - "license": { - "name": "New BSD", - "url": "http://opensource.org/licenses/BSD-3-Clause" - }, - "dependency": { - "name": "puma", - "url": "http://puma.io", - "description": "Puma is a simple, fast, threaded, and highly concurrent HTTP 1.1 server for Ruby/Rack applications", - "pathes": [ - "." - ] - } - }, - { - "license": { - "name": "MIT", - "url": "http://opensource.org/licenses/mit-license" - }, - "dependency": { - "name": "rack", - "url": "https://rack.github.io/", - "description": "a modular Ruby webserver interface", - "pathes": [ - "." - ] - } - }, - { - "license": { - "name": "MIT", - "url": "http://opensource.org/licenses/mit-license" - }, - "dependency": { - "name": "rack-test", - "url": "http://github.com/brynary/rack-test", - "description": "Simple testing API built on Rack", - "pathes": [ - "." - ] - } - }, - { - "license": { - "name": "MIT", - "url": "http://opensource.org/licenses/mit-license" - }, - "dependency": { - "name": "rails", - "url": "http://rubyonrails.org", - "description": "Full-stack web application framework.", - "pathes": [ - "." - ] - } - }, - { - "license": { - "name": "MIT", - "url": "http://opensource.org/licenses/mit-license" - }, - "dependency": { - "name": "rails-dom-testing", - "url": "https://github.com/rails/rails-dom-testing", - "description": "Dom and Selector assertions for Rails applications", - "pathes": [ - "." - ] - } - }, - { - "license": { - "name": "MIT", - "url": "http://opensource.org/licenses/mit-license" - }, - "dependency": { - "name": "rails-html-sanitizer", - "url": "https://github.com/rails/rails-html-sanitizer", - "description": "This gem is responsible to sanitize HTML fragments in Rails applications.", - "pathes": [ - "." - ] - } - }, - { - "license": { - "name": "MIT", - "url": "http://opensource.org/licenses/mit-license" - }, - "dependency": { - "name": "railties", - "url": "http://rubyonrails.org", - "description": "Tools for creating, working with, and running Rails applications.", - "pathes": [ - "." - ] - } - }, - { - "license": { - "name": "MIT", - "url": "http://opensource.org/licenses/mit-license" - }, - "dependency": { - "name": "rake", - "url": "https://github.com/ruby/rake", - "description": "Rake is a Make-like program implemented in Ruby", - "pathes": [ - "." - ] - } - }, - { - "license": { - "name": "MIT", - "url": "http://opensource.org/licenses/mit-license" - }, - "dependency": { - "name": "rb-fsevent", - "url": "http://rubygems.org/gems/rb-fsevent", - "description": "Very simple & usable FSEvents API", - "pathes": [ - "." - ] - } - }, - { - "license": { - "name": "MIT", - "url": "http://opensource.org/licenses/mit-license" - }, - "dependency": { - "name": "rb-inotify", - "url": "https://github.com/guard/rb-inotify", - "description": "A Ruby wrapper for Linux inotify, using FFI", - "pathes": [ - "." - ] - } - }, - { - "license": { - "name": "unknown" - }, - "dependency": { - "name": "ruby-bundler-rails", - "description": "", - "pathes": [ - "." - ] - } - }, - { - "license": { - "name": "MIT", - "url": "http://opensource.org/licenses/mit-license" - }, - "dependency": { - "name": "sass", - "url": "http://sass-lang.com/", - "description": "A powerful but elegant CSS compiler that makes CSS fun again.", - "pathes": [ - "." - ] - } - }, - { - "license": { - "name": "MIT", - "url": "http://opensource.org/licenses/mit-license" - }, - "dependency": { - "name": "sass-listen", - "url": "https://github.com/sass/listen", - "description": "Fork of guard/listen", - "pathes": [ - "." - ] - } - }, - { - "license": { - "name": "MIT", - "url": "http://opensource.org/licenses/mit-license" - }, - "dependency": { - "name": "sass-rails", - "url": "https://github.com/rails/sass-rails", - "description": "Sass adapter for the Rails asset pipeline.", - "pathes": [ - "." - ] - } - }, - { - "license": { - "name": "MIT", - "url": "http://opensource.org/licenses/mit-license" - }, - "dependency": { - "name": "sprockets", - "url": "https://github.com/rails/sprockets", - "description": "Rack-based asset packaging system", - "pathes": [ - "." - ] - } - }, - { - "license": { - "name": "MIT", - "url": "http://opensource.org/licenses/mit-license" - }, - "dependency": { - "name": "sprockets-rails", - "url": "https://github.com/rails/sprockets-rails", - "description": "Sprockets Rails integration", - "pathes": [ - "." - ] - } - }, - { - "license": { - "name": "New BSD", - "url": "http://opensource.org/licenses/BSD-3-Clause" - }, - "dependency": { - "name": "sqlite3", - "url": "https://github.com/sparklemotion/sqlite3-ruby", - "description": "This module allows Ruby programs to interface with the SQLite3 database engine (http://www.sqlite.org)", - "pathes": [ - "." - ] - } - }, - { - "license": { - "name": "MIT", - "url": "http://opensource.org/licenses/mit-license" - }, - "dependency": { - "name": "thor", - "url": "http://whatisthor.com/", - "description": "Thor is a toolkit for building powerful command-line interfaces.", - "pathes": [ - "." - ] - } - }, - { - "license": { - "name": "Apache 2.0", - "url": "http://www.apache.org/licenses/LICENSE-2.0.txt" - }, - "dependency": { - "name": "thread_safe", - "url": "https://github.com/ruby-concurrency/thread_safe", - "description": "Thread-safe collections and utilities for Ruby", - "pathes": [ - "." - ] - } - }, - { - "license": { - "name": "MIT", - "url": "http://opensource.org/licenses/mit-license" - }, - "dependency": { - "name": "tilt", - "url": "http://github.com/rtomayko/tilt/", - "description": "Generic interface to multiple Ruby template engines", - "pathes": [ - "." - ] - } - }, - { - "license": { - "name": "MIT", - "url": "http://opensource.org/licenses/mit-license" - }, - "dependency": { - "name": "turbolinks", - "url": "https://github.com/turbolinks/turbolinks", - "description": "Turbolinks makes navigating your web application faster", - "pathes": [ - "." - ] - } - }, - { - "license": { - "name": "MIT", - "url": "http://opensource.org/licenses/mit-license" - }, - "dependency": { - "name": "turbolinks-source", - "url": "https://github.com/turbolinks/turbolinks-source-gem", - "description": "Turbolinks JavaScript assets", - "pathes": [ - "." - ] - } - }, - { - "license": { - "name": "MIT", - "url": "http://opensource.org/licenses/mit-license" - }, - "dependency": { - "name": "tzinfo", - "url": "http://tzinfo.github.io", - "description": "Daylight savings aware timezone library", - "pathes": [ - "." - ] - } - }, - { - "license": { - "name": "MIT", - "url": "http://opensource.org/licenses/mit-license" - }, - "dependency": { - "name": "uglifier", - "url": "http://github.com/lautis/uglifier", - "description": "Ruby wrapper for UglifyJS JavaScript compressor", - "pathes": [ - "." - ] - } - }, - { - "license": { - "name": "MIT", - "url": "http://opensource.org/licenses/mit-license" - }, - "dependency": { - "name": "websocket-driver", - "url": "http://github.com/faye/websocket-driver-ruby", - "description": "WebSocket protocol handler with pluggable I/O", - "pathes": [ - "." - ] - } - }, - { - "license": { - "name": "MIT", - "url": "http://opensource.org/licenses/mit-license" - }, - "dependency": { - "name": "websocket-extensions", - "url": "https://github.com/faye/websocket-extensions-ruby", - "description": "Generic extension manager for WebSocket connections", - "pathes": [ - "." - ] - } - } - ] -} diff --git a/spec/fixtures/security-reports/master/gl-sast-report.json b/spec/fixtures/security-reports/master/gl-sast-report.json deleted file mode 100644 index 345e1e9f83a..00000000000 --- a/spec/fixtures/security-reports/master/gl-sast-report.json +++ /dev/null @@ -1,967 +0,0 @@ -{ - "version": "1.2", - "vulnerabilities": [ - { - "category": "sast", - "message": "Probable insecure usage of temp file/directory.", - "cve": "python/hardcoded/hardcoded-tmp.py:52865813c884a507be1f152d654245af34aba8a391626d01f1ab6d3f52ec8779:B108", - "severity": "Medium", - "confidence": "Medium", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/hardcoded/hardcoded-tmp.py", - "start_line": 1, - "end_line": 1 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B108", - "value": "B108", - "url": "https://docs.openstack.org/bandit/latest/plugins/b108_hardcoded_tmp_directory.html" - } - ], - "priority": "Medium", - "file": "python/hardcoded/hardcoded-tmp.py", - "line": 1, - "url": "https://docs.openstack.org/bandit/latest/plugins/b108_hardcoded_tmp_directory.html", - "tool": "bandit" - }, - { - "category": "sast", - "name": "Predictable pseudorandom number generator", - "message": "Predictable pseudorandom number generator", - "cve": "groovy/src/main/java/com/gitlab/security_products/tests/App.groovy:47:PREDICTABLE_RANDOM", - "severity": "Medium", - "confidence": "Medium", - "scanner": { - "id": "find_sec_bugs", - "name": "Find Security Bugs" - }, - "location": { - "file": "groovy/src/main/java/com/gitlab/security_products/tests/App.groovy", - "start_line": 47, - "end_line": 47, - "class": "com.gitlab.security_products.tests.App", - "method": "generateSecretToken2" - }, - "identifiers": [ - { - "type": "find_sec_bugs_type", - "name": "Find Security Bugs-PREDICTABLE_RANDOM", - "value": "PREDICTABLE_RANDOM", - "url": "https://find-sec-bugs.github.io/bugs.htm#PREDICTABLE_RANDOM" - } - ], - "priority": "Medium", - "file": "groovy/src/main/java/com/gitlab/security_products/tests/App.groovy", - "line": 47, - "url": "https://find-sec-bugs.github.io/bugs.htm#PREDICTABLE_RANDOM", - "tool": "find_sec_bugs" - }, - { - "category": "sast", - "name": "Predictable pseudorandom number generator", - "message": "Predictable pseudorandom number generator", - "cve": "groovy/src/main/java/com/gitlab/security_products/tests/App.groovy:41:PREDICTABLE_RANDOM", - "severity": "Medium", - "confidence": "Medium", - "scanner": { - "id": "find_sec_bugs", - "name": "Find Security Bugs" - }, - "location": { - "file": "groovy/src/main/java/com/gitlab/security_products/tests/App.groovy", - "start_line": 41, - "end_line": 41, - "class": "com.gitlab.security_products.tests.App", - "method": "generateSecretToken1" - }, - "identifiers": [ - { - "type": "find_sec_bugs_type", - "name": "Find Security Bugs-PREDICTABLE_RANDOM", - "value": "PREDICTABLE_RANDOM", - "url": "https://find-sec-bugs.github.io/bugs.htm#PREDICTABLE_RANDOM" - } - ], - "priority": "Medium", - "file": "groovy/src/main/java/com/gitlab/security_products/tests/App.groovy", - "line": 41, - "url": "https://find-sec-bugs.github.io/bugs.htm#PREDICTABLE_RANDOM", - "tool": "find_sec_bugs" - }, - { - "category": "sast", - "message": "Use of insecure MD2, MD4, or MD5 hash function.", - "cve": "python/imports/imports-aliases.py:cb203b465dffb0cb3a8e8bd8910b84b93b0a5995a938e4b903dbb0cd6ffa1254:B303", - "severity": "Medium", - "confidence": "High", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/imports/imports-aliases.py", - "start_line": 11, - "end_line": 11 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B303", - "value": "B303" - } - ], - "priority": "Medium", - "file": "python/imports/imports-aliases.py", - "line": 11, - "tool": "bandit" - }, - { - "category": "sast", - "message": "Use of insecure MD2, MD4, or MD5 hash function.", - "cve": "python/imports/imports-aliases.py:a7173c43ae66bd07466632d819d450e0071e02dbf782763640d1092981f9631b:B303", - "severity": "Medium", - "confidence": "High", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/imports/imports-aliases.py", - "start_line": 12, - "end_line": 12 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B303", - "value": "B303" - } - ], - "priority": "Medium", - "file": "python/imports/imports-aliases.py", - "line": 12, - "tool": "bandit" - }, - { - "category": "sast", - "message": "Use of insecure MD2, MD4, or MD5 hash function.", - "cve": "python/imports/imports-aliases.py:017017b77deb0b8369b6065947833eeea752a92ec8a700db590fece3e934cf0d:B303", - "severity": "Medium", - "confidence": "High", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/imports/imports-aliases.py", - "start_line": 13, - "end_line": 13 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B303", - "value": "B303" - } - ], - "priority": "Medium", - "file": "python/imports/imports-aliases.py", - "line": 13, - "tool": "bandit" - }, - { - "category": "sast", - "message": "Use of insecure MD2, MD4, or MD5 hash function.", - "cve": "python/imports/imports-aliases.py:45fc8c53aea7b84f06bc4e590cc667678d6073c4c8a1d471177ca2146fb22db2:B303", - "severity": "Medium", - "confidence": "High", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/imports/imports-aliases.py", - "start_line": 14, - "end_line": 14 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B303", - "value": "B303" - } - ], - "priority": "Medium", - "file": "python/imports/imports-aliases.py", - "line": 14, - "tool": "bandit" - }, - { - "category": "sast", - "message": "Pickle library appears to be in use, possible security issue.", - "cve": "python/imports/imports-aliases.py:5f200d47291e7bbd8352db23019b85453ca048dd98ea0c291260fa7d009963a4:B301", - "severity": "Medium", - "confidence": "High", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/imports/imports-aliases.py", - "start_line": 15, - "end_line": 15 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B301", - "value": "B301" - } - ], - "priority": "Medium", - "file": "python/imports/imports-aliases.py", - "line": 15, - "tool": "bandit" - }, - { - "category": "sast", - "name": "ECB mode is insecure", - "message": "ECB mode is insecure", - "cve": "groovy/src/main/java/com/gitlab/security_products/tests/App.groovy:29:ECB_MODE", - "severity": "Medium", - "confidence": "High", - "scanner": { - "id": "find_sec_bugs", - "name": "Find Security Bugs" - }, - "location": { - "file": "groovy/src/main/java/com/gitlab/security_products/tests/App.groovy", - "start_line": 29, - "end_line": 29, - "class": "com.gitlab.security_products.tests.App", - "method": "insecureCypher" - }, - "identifiers": [ - { - "type": "find_sec_bugs_type", - "name": "Find Security Bugs-ECB_MODE", - "value": "ECB_MODE", - "url": "https://find-sec-bugs.github.io/bugs.htm#ECB_MODE" - } - ], - "priority": "Medium", - "file": "groovy/src/main/java/com/gitlab/security_products/tests/App.groovy", - "line": 29, - "url": "https://find-sec-bugs.github.io/bugs.htm#ECB_MODE", - "tool": "find_sec_bugs" - }, - { - "category": "sast", - "name": "Cipher with no integrity", - "message": "Cipher with no integrity", - "cve": "groovy/src/main/java/com/gitlab/security_products/tests/App.groovy:29:CIPHER_INTEGRITY", - "severity": "Medium", - "confidence": "High", - "scanner": { - "id": "find_sec_bugs", - "name": "Find Security Bugs" - }, - "location": { - "file": "groovy/src/main/java/com/gitlab/security_products/tests/App.groovy", - "start_line": 29, - "end_line": 29, - "class": "com.gitlab.security_products.tests.App", - "method": "insecureCypher" - }, - "identifiers": [ - { - "type": "find_sec_bugs_type", - "name": "Find Security Bugs-CIPHER_INTEGRITY", - "value": "CIPHER_INTEGRITY", - "url": "https://find-sec-bugs.github.io/bugs.htm#CIPHER_INTEGRITY" - } - ], - "priority": "Medium", - "file": "groovy/src/main/java/com/gitlab/security_products/tests/App.groovy", - "line": 29, - "url": "https://find-sec-bugs.github.io/bugs.htm#CIPHER_INTEGRITY", - "tool": "find_sec_bugs" - }, - { - "category": "sast", - "message": "Probable insecure usage of temp file/directory.", - "cve": "python/hardcoded/hardcoded-tmp.py:63dd4d626855555b816985d82c4614a790462a0a3ada89dc58eb97f9c50f3077:B108", - "severity": "Medium", - "confidence": "Medium", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/hardcoded/hardcoded-tmp.py", - "start_line": 14, - "end_line": 14 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B108", - "value": "B108", - "url": "https://docs.openstack.org/bandit/latest/plugins/b108_hardcoded_tmp_directory.html" - } - ], - "priority": "Medium", - "file": "python/hardcoded/hardcoded-tmp.py", - "line": 14, - "url": "https://docs.openstack.org/bandit/latest/plugins/b108_hardcoded_tmp_directory.html", - "tool": "bandit" - }, - { - "category": "sast", - "message": "Probable insecure usage of temp file/directory.", - "cve": "python/hardcoded/hardcoded-tmp.py:4ad6d4c40a8c263fc265f3384724014e0a4f8dd6200af83e51ff120420038031:B108", - "severity": "Medium", - "confidence": "Medium", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/hardcoded/hardcoded-tmp.py", - "start_line": 10, - "end_line": 10 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B108", - "value": "B108", - "url": "https://docs.openstack.org/bandit/latest/plugins/b108_hardcoded_tmp_directory.html" - } - ], - "priority": "Medium", - "file": "python/hardcoded/hardcoded-tmp.py", - "line": 10, - "url": "https://docs.openstack.org/bandit/latest/plugins/b108_hardcoded_tmp_directory.html", - "tool": "bandit" - }, - { - "category": "sast", - "message": "Consider possible security implications associated with Popen module.", - "cve": "python/imports/imports-aliases.py:2c3e1fa1e54c3c6646e8bcfaee2518153c6799b77587ff8d9a7b0631f6d34785:B404", - "severity": "Low", - "confidence": "High", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/imports/imports-aliases.py", - "start_line": 1, - "end_line": 1 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B404", - "value": "B404" - } - ], - "priority": "Low", - "file": "python/imports/imports-aliases.py", - "line": 1, - "tool": "bandit" - }, - { - "category": "sast", - "message": "Consider possible security implications associated with pickle module.", - "cve": "python/imports/imports.py:af58d07f6ad519ef5287fcae65bf1a6999448a1a3a8bc1ac2a11daa80d0b96bf:B403", - "severity": "Low", - "confidence": "High", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/imports/imports.py", - "start_line": 2, - "end_line": 2 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B403", - "value": "B403" - } - ], - "priority": "Low", - "file": "python/imports/imports.py", - "line": 2, - "tool": "bandit" - }, - { - "category": "sast", - "message": "Consider possible security implications associated with subprocess module.", - "cve": "python/imports/imports.py:8de9bc98029d212db530785a5f6780cfa663548746ff228ab8fa96c5bb82f089:B404", - "severity": "Low", - "confidence": "High", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/imports/imports.py", - "start_line": 4, - "end_line": 4 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B404", - "value": "B404" - } - ], - "priority": "Low", - "file": "python/imports/imports.py", - "line": 4, - "tool": "bandit" - }, - { - "category": "sast", - "message": "Possible hardcoded password: 'blerg'", - "cve": "python/hardcoded/hardcoded-passwords.py:97c30f1d76d2a88913e3ce9ae74087874d740f87de8af697a9c455f01119f633:B106", - "severity": "Low", - "confidence": "Medium", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/hardcoded/hardcoded-passwords.py", - "start_line": 22, - "end_line": 22 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B106", - "value": "B106", - "url": "https://docs.openstack.org/bandit/latest/plugins/b106_hardcoded_password_funcarg.html" - } - ], - "priority": "Low", - "file": "python/hardcoded/hardcoded-passwords.py", - "line": 22, - "url": "https://docs.openstack.org/bandit/latest/plugins/b106_hardcoded_password_funcarg.html", - "tool": "bandit" - }, - { - "category": "sast", - "message": "Possible hardcoded password: 'root'", - "cve": "python/hardcoded/hardcoded-passwords.py:7431c73a0bc16d94ece2a2e75ef38f302574d42c37ac0c3c38ad0b3bf8a59f10:B105", - "severity": "Low", - "confidence": "Medium", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/hardcoded/hardcoded-passwords.py", - "start_line": 5, - "end_line": 5 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B105", - "value": "B105", - "url": "https://docs.openstack.org/bandit/latest/plugins/b105_hardcoded_password_string.html" - } - ], - "priority": "Low", - "file": "python/hardcoded/hardcoded-passwords.py", - "line": 5, - "url": "https://docs.openstack.org/bandit/latest/plugins/b105_hardcoded_password_string.html", - "tool": "bandit" - }, - { - "category": "sast", - "message": "Possible hardcoded password: ''", - "cve": "python/hardcoded/hardcoded-passwords.py:d2d1857c27caedd49c57bfbcdc23afcc92bd66a22701fcdc632869aab4ca73ee:B105", - "severity": "Low", - "confidence": "Medium", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/hardcoded/hardcoded-passwords.py", - "start_line": 9, - "end_line": 9 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B105", - "value": "B105", - "url": "https://docs.openstack.org/bandit/latest/plugins/b105_hardcoded_password_string.html" - } - ], - "priority": "Low", - "file": "python/hardcoded/hardcoded-passwords.py", - "line": 9, - "url": "https://docs.openstack.org/bandit/latest/plugins/b105_hardcoded_password_string.html", - "tool": "bandit" - }, - { - "category": "sast", - "message": "Possible hardcoded password: 'ajklawejrkl42348swfgkg'", - "cve": "python/hardcoded/hardcoded-passwords.py:fb3866215a61393a5c9c32a3b60e2058171a23219c353f722cbd3567acab21d2:B105", - "severity": "Low", - "confidence": "Medium", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/hardcoded/hardcoded-passwords.py", - "start_line": 13, - "end_line": 13 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B105", - "value": "B105", - "url": "https://docs.openstack.org/bandit/latest/plugins/b105_hardcoded_password_string.html" - } - ], - "priority": "Low", - "file": "python/hardcoded/hardcoded-passwords.py", - "line": 13, - "url": "https://docs.openstack.org/bandit/latest/plugins/b105_hardcoded_password_string.html", - "tool": "bandit" - }, - { - "category": "sast", - "message": "Possible hardcoded password: 'blerg'", - "cve": "python/hardcoded/hardcoded-passwords.py:63c62a8b7e1e5224439bd26b28030585ac48741e28ca64561a6071080c560a5f:B105", - "severity": "Low", - "confidence": "Medium", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/hardcoded/hardcoded-passwords.py", - "start_line": 23, - "end_line": 23 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B105", - "value": "B105", - "url": "https://docs.openstack.org/bandit/latest/plugins/b105_hardcoded_password_string.html" - } - ], - "priority": "Low", - "file": "python/hardcoded/hardcoded-passwords.py", - "line": 23, - "url": "https://docs.openstack.org/bandit/latest/plugins/b105_hardcoded_password_string.html", - "tool": "bandit" - }, - { - "category": "sast", - "message": "Possible hardcoded password: 'blerg'", - "cve": "python/hardcoded/hardcoded-passwords.py:4311b06d08df8fa58229b341c531da8e1a31ec4520597bdff920cd5c098d86f9:B105", - "severity": "Low", - "confidence": "Medium", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/hardcoded/hardcoded-passwords.py", - "start_line": 24, - "end_line": 24 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B105", - "value": "B105", - "url": "https://docs.openstack.org/bandit/latest/plugins/b105_hardcoded_password_string.html" - } - ], - "priority": "Low", - "file": "python/hardcoded/hardcoded-passwords.py", - "line": 24, - "url": "https://docs.openstack.org/bandit/latest/plugins/b105_hardcoded_password_string.html", - "tool": "bandit" - }, - { - "category": "sast", - "message": "Consider possible security implications associated with subprocess module.", - "cve": "python/imports/imports-function.py:5858400c2f39047787702de44d03361ef8d954c9d14bd54ee1c2bef9e6a7df93:B404", - "severity": "Low", - "confidence": "High", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/imports/imports-function.py", - "start_line": 4, - "end_line": 4 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B404", - "value": "B404" - } - ], - "priority": "Low", - "file": "python/imports/imports-function.py", - "line": 4, - "tool": "bandit" - }, - { - "category": "sast", - "message": "Consider possible security implications associated with pickle module.", - "cve": "python/imports/imports-function.py:dbda3cf4190279d30e0aad7dd137eca11272b0b225e8af4e8bf39682da67d956:B403", - "severity": "Low", - "confidence": "High", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/imports/imports-function.py", - "start_line": 2, - "end_line": 2 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B403", - "value": "B403" - } - ], - "priority": "Low", - "file": "python/imports/imports-function.py", - "line": 2, - "tool": "bandit" - }, - { - "category": "sast", - "message": "Consider possible security implications associated with Popen module.", - "cve": "python/imports/imports-from.py:eb8a0db9cd1a8c1ab39a77e6025021b1261cc2a0b026b2f4a11fca4e0636d8dd:B404", - "severity": "Low", - "confidence": "High", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/imports/imports-from.py", - "start_line": 7, - "end_line": 7 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B404", - "value": "B404" - } - ], - "priority": "Low", - "file": "python/imports/imports-from.py", - "line": 7, - "tool": "bandit" - }, - { - "category": "sast", - "message": "subprocess call with shell=True seems safe, but may be changed in the future, consider rewriting without shell", - "cve": "python/imports/imports-aliases.py:f99f9721e27537fbcb6699a4cf39c6740d6234d2c6f06cfc2d9ea977313c483d:B602", - "severity": "Low", - "confidence": "High", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/imports/imports-aliases.py", - "start_line": 9, - "end_line": 9 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B602", - "value": "B602", - "url": "https://docs.openstack.org/bandit/latest/plugins/b602_subprocess_popen_with_shell_equals_true.html" - } - ], - "priority": "Low", - "file": "python/imports/imports-aliases.py", - "line": 9, - "url": "https://docs.openstack.org/bandit/latest/plugins/b602_subprocess_popen_with_shell_equals_true.html", - "tool": "bandit" - }, - { - "category": "sast", - "message": "Consider possible security implications associated with subprocess module.", - "cve": "python/imports/imports-from.py:332a12ab1146698f614a905ce6a6a5401497a12281aef200e80522711c69dcf4:B404", - "severity": "Low", - "confidence": "High", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/imports/imports-from.py", - "start_line": 6, - "end_line": 6 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B404", - "value": "B404" - } - ], - "priority": "Low", - "file": "python/imports/imports-from.py", - "line": 6, - "tool": "bandit" - }, - { - "category": "sast", - "message": "Consider possible security implications associated with Popen module.", - "cve": "python/imports/imports-from.py:0a48de4a3d5348853a03666cb574697e3982998355e7a095a798bd02a5947276:B404", - "severity": "Low", - "confidence": "High", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/imports/imports-from.py", - "start_line": 1, - "end_line": 2 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B404", - "value": "B404" - } - ], - "priority": "Low", - "file": "python/imports/imports-from.py", - "line": 1, - "tool": "bandit" - }, - { - "category": "sast", - "message": "Consider possible security implications associated with pickle module.", - "cve": "python/imports/imports-aliases.py:51b71661dff994bde3529639a727a678c8f5c4c96f00d300913f6d5be1bbdf26:B403", - "severity": "Low", - "confidence": "High", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/imports/imports-aliases.py", - "start_line": 7, - "end_line": 8 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B403", - "value": "B403" - } - ], - "priority": "Low", - "file": "python/imports/imports-aliases.py", - "line": 7, - "tool": "bandit" - }, - { - "category": "sast", - "message": "Consider possible security implications associated with loads module.", - "cve": "python/imports/imports-aliases.py:6ff02aeb3149c01ab68484d794a94f58d5d3e3bb0d58557ef4153644ea68ea54:B403", - "severity": "Low", - "confidence": "High", - "scanner": { - "id": "bandit", - "name": "Bandit" - }, - "location": { - "file": "python/imports/imports-aliases.py", - "start_line": 6, - "end_line": 6 - }, - "identifiers": [ - { - "type": "bandit_test_id", - "name": "Bandit Test ID B403", - "value": "B403" - } - ], - "priority": "Low", - "file": "python/imports/imports-aliases.py", - "line": 6, - "tool": "bandit" - }, - { - "category": "sast", - "message": "Statically-sized arrays can be improperly restricted, leading to potential overflows or other issues (CWE-119!/CWE-120)", - "cve": "c/subdir/utils.c:b466873101951fe96e1332f6728eb7010acbbd5dfc3b65d7d53571d091a06d9e:CWE-119!/CWE-120", - "confidence": "Low", - "solution": "Perform bounds checking, use functions that limit length, or ensure that the size is larger than the maximum possible length", - "scanner": { - "id": "flawfinder", - "name": "Flawfinder" - }, - "location": { - "file": "c/subdir/utils.c", - "start_line": 4 - }, - "identifiers": [ - { - "type": "flawfinder_func_name", - "name": "Flawfinder - char", - "value": "char" - }, - { - "type": "cwe", - "name": "CWE-119", - "value": "119", - "url": "https://cwe.mitre.org/data/definitions/119.html" - }, - { - "type": "cwe", - "name": "CWE-120", - "value": "120", - "url": "https://cwe.mitre.org/data/definitions/120.html" - } - ], - "file": "c/subdir/utils.c", - "line": 4, - "url": "https://cwe.mitre.org/data/definitions/119.html", - "tool": "flawfinder" - }, - { - "category": "sast", - "message": "Check when opening files - can an attacker redirect it (via symlinks), force the opening of special file type (e.g., device files), move things around to create a race condition, control its ancestors, or change its contents? (CWE-362)", - "cve": "c/subdir/utils.c:bab681140fcc8fc3085b6bba74081b44ea145c1c98b5e70cf19ace2417d30770:CWE-362", - "confidence": "Low", - "scanner": { - "id": "flawfinder", - "name": "Flawfinder" - }, - "location": { - "file": "c/subdir/utils.c", - "start_line": 8 - }, - "identifiers": [ - { - "type": "flawfinder_func_name", - "name": "Flawfinder - fopen", - "value": "fopen" - }, - { - "type": "cwe", - "name": "CWE-362", - "value": "362", - "url": "https://cwe.mitre.org/data/definitions/362.html" - } - ], - "file": "c/subdir/utils.c", - "line": 8, - "url": "https://cwe.mitre.org/data/definitions/362.html", - "tool": "flawfinder" - }, - { - "category": "sast", - "message": "Statically-sized arrays can be improperly restricted, leading to potential overflows or other issues (CWE-119!/CWE-120)", - "cve": "cplusplus/src/hello.cpp:c8c6dd0afdae6814194cf0930b719f757ab7b379cf8f261e7f4f9f2f323a818a:CWE-119!/CWE-120", - "confidence": "Low", - "solution": "Perform bounds checking, use functions that limit length, or ensure that the size is larger than the maximum possible length", - "scanner": { - "id": "flawfinder", - "name": "Flawfinder" - }, - "location": { - "file": "cplusplus/src/hello.cpp", - "start_line": 6 - }, - "identifiers": [ - { - "type": "flawfinder_func_name", - "name": "Flawfinder - char", - "value": "char" - }, - { - "type": "cwe", - "name": "CWE-119", - "value": "119", - "url": "https://cwe.mitre.org/data/definitions/119.html" - }, - { - "type": "cwe", - "name": "CWE-120", - "value": "120", - "url": "https://cwe.mitre.org/data/definitions/120.html" - } - ], - "file": "cplusplus/src/hello.cpp", - "line": 6, - "url": "https://cwe.mitre.org/data/definitions/119.html", - "tool": "flawfinder" - }, - { - "category": "sast", - "message": "Does not check for buffer overflows when copying to destination [MS-banned] (CWE-120)", - "cve": "cplusplus/src/hello.cpp:331c04062c4fe0c7c486f66f59e82ad146ab33cdd76ae757ca41f392d568cbd0:CWE-120", - "confidence": "Low", - "solution": "Consider using snprintf, strcpy_s, or strlcpy (warning: strncpy easily misused)", - "scanner": { - "id": "flawfinder", - "name": "Flawfinder" - }, - "location": { - "file": "cplusplus/src/hello.cpp", - "start_line": 7 - }, - "identifiers": [ - { - "type": "flawfinder_func_name", - "name": "Flawfinder - strcpy", - "value": "strcpy" - }, - { - "type": "cwe", - "name": "CWE-120", - "value": "120", - "url": "https://cwe.mitre.org/data/definitions/120.html" - } - ], - "file": "cplusplus/src/hello.cpp", - "line": 7, - "url": "https://cwe.mitre.org/data/definitions/120.html", - "tool": "flawfinder" - } - ] -} diff --git a/spec/fixtures/security-reports/remediations/gl-dependency-scanning-report.json b/spec/fixtures/security-reports/remediations/gl-dependency-scanning-report.json deleted file mode 100644 index c96e831b027..00000000000 --- a/spec/fixtures/security-reports/remediations/gl-dependency-scanning-report.json +++ /dev/null @@ -1,104 +0,0 @@ -{ - "version": "2.0", - "vulnerabilities": [ - { - "category": "dependency_scanning", - "name": "Regular Expression Denial of Service", - "message": "Regular Expression Denial of Service in debug", - "description": "The debug module is vulnerable to regular expression denial of service when untrusted user input is passed into the `o` formatter. It takes around 50k characters to block for 2 seconds making this a low severity issue.", - "cve": "yarn.lock:debug:gemnasium:37283ed4-0380-40d7-ada7-2d994afcc62a", - "severity": "Unknown", - "solution": "Upgrade to latest versions.", - "scanner": { - "id": "gemnasium", - "name": "Gemnasium" - }, - "location": { - "file": "yarn.lock", - "dependency": { - "package": { - "name": "debug" - }, - "version": "1.0.5" - } - }, - "identifiers": [ - { - "type": "gemnasium", - "name": "Gemnasium-37283ed4-0380-40d7-ada7-2d994afcc62a", - "value": "37283ed4-0380-40d7-ada7-2d994afcc62a", - "url": "https://deps.sec.gitlab.com/packages/npm/debug/versions/1.0.5/advisories" - } - ], - "links": [ - { - "url": "https://nodesecurity.io/advisories/534" - }, - { - "url": "https://github.com/visionmedia/debug/issues/501" - }, - { - "url": "https://github.com/visionmedia/debug/pull/504" - } - ] - }, - { - "category": "dependency_scanning", - "name": "Authentication bypass via incorrect DOM traversal and canonicalization", - "message": "Authentication bypass via incorrect DOM traversal and canonicalization in saml2-js", - "description": "Some XML DOM traversal and canonicalization APIs may be inconsistent in handling of comments within XML nodes. Incorrect use of these APIs by some SAML libraries results in incorrect parsing of the inner text of XML nodes such that any inner text after the comment is lost prior to cryptographically signing the SAML message. Text after the comment therefore has no impact on the signature on the SAML message.\r\n\r\nA remote attacker can modify SAML content for a SAML service provider without invalidating the cryptographic signature, which may allow attackers to bypass primary authentication for the affected SAML service provider.", - "cve": "yarn.lock:saml2-js:gemnasium:9952e574-7b5b-46fa-a270-aeb694198a98", - "severity": "Unknown", - "solution": "Upgrade to fixed version.\r\n", - "scanner": { - "id": "gemnasium", - "name": "Gemnasium" - }, - "location": { - "file": "yarn.lock", - "dependency": { - "package": { - "name": "saml2-js" - }, - "version": "1.5.0" - } - }, - "identifiers": [ - { - "type": "gemnasium", - "name": "Gemnasium-9952e574-7b5b-46fa-a270-aeb694198a98", - "value": "9952e574-7b5b-46fa-a270-aeb694198a98", - "url": "https://deps.sec.gitlab.com/packages/npm/saml2-js/versions/1.5.0/advisories" - }, - { - "type": "cve", - "name": "CVE-2017-11429", - "value": "CVE-2017-11429", - "url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-11429" - } - ], - "links": [ - { - "url": "https://github.com/Clever/saml2/commit/3546cb61fd541f219abda364c5b919633609ef3d#diff-af730f9f738de1c9ad87596df3f6de84R279" - }, - { - "url": "https://github.com/Clever/saml2/issues/127" - }, - { - "url": "https://www.kb.cert.org/vuls/id/475445" - } - ] - } - ], - "remediations": [ - { - "fixes": [ - { - "cve": "yarn.lock:saml2-js:gemnasium:9952e574-7b5b-46fa-a270-aeb694198a98" - } - ], - "summary": "Upgrade saml2-js", - "diff": "ZGlmZiAtLWdpdCBhL3lhcm4ubG9jayBiL3lhcm4ubG9jawppbmRleCAwZWNjOTJmLi43ZmE0NTU0IDEwMDY0NAotLS0gYS95YXJuLmxvY2sKKysrIGIveWFybi5sb2NrCkBAIC0yLDEwMyArMiwxMjQgQEAKICMgeWFybiBsb2NrZmlsZSB2MQogCiAKLWFzeW5jQH4wLjIuNzoKLSAgdmVyc2lvbiAiMC4yLjEwIgotICByZXNvbHZlZCAiaHR0cDovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9hc3luYy8tL2FzeW5jLTAuMi4xMC50Z3ojYjZiYmUwYjA2NzRiOWQ3MTk3MDhjYTM4ZGU4YzIzN2NiNTI2YzNkMSIKLQotYXN5bmNAfjEuNS4yOgotICB2ZXJzaW9uICIxLjUuMiIKLSAgcmVzb2x2ZWQgImh0dHA6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvYXN5bmMvLS9hc3luYy0xLjUuMi50Z3ojZWM2YTYxYWU1NjQ4MGMwYzNjYjI0MWM5NTYxOGUyMDg5MmY5NjcyYSIKK2FzeW5jQF4yLjEuNSwgYXN5bmNAXjIuNS4wOgorICB2ZXJzaW9uICIyLjYuMSIKKyAgcmVzb2x2ZWQgImh0dHBzOi8vcmVnaXN0cnkueWFybnBrZy5jb20vYXN5bmMvLS9hc3luYy0yLjYuMS50Z3ojYjI0NWEyM2NhNzE5MzAwNDRlYzUzZmE0NmFhMDBhM2U4N2M2YTYxMCIKKyAgaW50ZWdyaXR5IHNoYTUxMi1mTkVpTDIrQVp0NkFsQXcvMjlDcjBVRGU0c1JBSENwRUhoNTRXTXorQmI3UWZOY0Z3NGgzbG9vZnlKcExlUXM0WXg3eXVxdS8yZExnTTVoS09zNkhsUT09CisgIGRlcGVuZGVuY2llczoKKyAgICBsb2Rhc2ggIl40LjE3LjEwIgogCi1kZWJ1Z0BeMS4wLjQ6Ci0gIHZlcnNpb24gIjEuMC41IgotICByZXNvbHZlZCAiaHR0cHM6Ly9yZWdpc3RyeS55YXJucGtnLmNvbS9kZWJ1Zy8tL2RlYnVnLTEuMC41LnRneiNmNzI0MTIxNzQzMGY5OWRlYzRjMmI0NzNlYWI5MjIyOGU4NzRjMmFjIgorZGVidWdAXjIuNi4wOgorICB2ZXJzaW9uICIyLjYuOSIKKyAgcmVzb2x2ZWQgImh0dHBzOi8vcmVnaXN0cnkueWFybnBrZy5jb20vZGVidWcvLS9kZWJ1Zy0yLjYuOS50Z3ojNWQxMjg1MTVkZjEzNGZmMzI3ZTkwYTRjOTNmNGUwNzdhNTM2MzQxZiIKKyAgaW50ZWdyaXR5IHNoYTUxMi1iQzdFbHJkSmFKblBiQVArMUVvdFl2cVpzYjNlY2w1d2k2QmZpNkJKVFVjTm93cDZjdnNwZzBqWHpuUlRLRGptL0U3QWRnRkJWZUFQVk1OY0tHc0hNQT09CiAgIGRlcGVuZGVuY2llczoKICAgICBtcyAiMi4wLjAiCiAKLWVqc0B+MC44LjM6Ci0gIHZlcnNpb24gIjAuOC44IgotICByZXNvbHZlZCAiaHR0cHM6Ly9yZWdpc3RyeS55YXJucGtnLmNvbS9lanMvLS9lanMtMC44LjgudGd6I2ZmZGM1NmRjYzM1ZDAyOTI2ZGQ1MGFkMTM0MzliYmM1NDA2MWQ1OTgiCitlanNAXjIuNS42OgorICB2ZXJzaW9uICIyLjYuMSIKKyAgcmVzb2x2ZWQgImh0dHBzOi8vcmVnaXN0cnkueWFybnBrZy5jb20vZWpzLy0vZWpzLTIuNi4xLnRneiM0OThlYzBkNDk1NjU1YWJjNmYyM2NkNjE4NjhkOTI2NDY0MDcxYWEwIgorICBpbnRlZ3JpdHkgc2hhNTEyLTB4eTRBL3R3ZnJSQ25raGZrOEVyRGk1RHFkQXNBcWVHeGh0NHhrQ1Vyc3ZoaGJRTnM3RSs0alYwQ043K05LSVkwYUhFNzIrWHZxdEJJWHpEMzFaYlhRPT0KKworbG9kYXNoLW5vZGVAfjIuNC4xOgorICB2ZXJzaW9uICIyLjQuMSIKKyAgcmVzb2x2ZWQgImh0dHBzOi8vcmVnaXN0cnkueWFybnBrZy5jb20vbG9kYXNoLW5vZGUvLS9sb2Rhc2gtbm9kZS0yLjQuMS50Z3ojZWE4MmY3YjEwMGM3MzNkMWE0MmFmNzY4MDFlNTA2MTA1ZTJhODBlYyIKKyAgaW50ZWdyaXR5IHNoYTEtNm9MM3NRREhNOUdrS3Zkb0FlVUdFRjRxZ093PQorCitsb2Rhc2hAXjQuMTcuMTA6CisgIHZlcnNpb24gIjQuMTcuMTEiCisgIHJlc29sdmVkICJodHRwczovL3JlZ2lzdHJ5Lnlhcm5wa2cuY29tL2xvZGFzaC8tL2xvZGFzaC00LjE3LjExLnRneiNiMzllYTYyMjllZjYwN2VjZDg5ZTJjOGRmMTI1MzY4OTFjYWM5YjhkIgorICBpbnRlZ3JpdHkgc2hhNTEyLWNRS2g4aWdvNVFVaFo3bGczOERZV0F4TXZqU0FLRzBBOHdHU1ZpbVAwN1NJVUVLMlVPK2FyU1JLYlJaV3RlbE10TjVWMEhrd2g1cnlPdG8vU3NoWUlnPT0KIAogbXNAMi4wLjA6CiAgIHZlcnNpb24gIjIuMC4wIgogICByZXNvbHZlZCAiaHR0cHM6Ly9yZWdpc3RyeS55YXJucGtnLmNvbS9tcy8tL21zLTIuMC4wLnRneiM1NjA4YWVhZGZjMDBiZTZjMjkwMWRmNWY5ODYxNzg4ZGUwZDU5N2M4IgorICBpbnRlZ3JpdHkgc2hhMS1WZ2l1cmZ3QXZtd3BBZDlmbUdGNGplRFZsOGc9CiAKLW5vZGUtZm9yZ2VAMC4yLjI0OgotICB2ZXJzaW9uICIwLjIuMjQiCi0gIHJlc29sdmVkICJodHRwczovL3JlZ2lzdHJ5Lnlhcm5wa2cuY29tL25vZGUtZm9yZ2UvLS9ub2RlLWZvcmdlLTAuMi4yNC50Z3ojZmE2Zjg0NmY0MmZhOTNmNjNhMGEzMGM5ZmJmZjdiNGUxMzBlMDg1OCIKK25vZGUtZm9yZ2VAXjAuNy4wOgorICB2ZXJzaW9uICIwLjcuNiIKKyAgcmVzb2x2ZWQgImh0dHBzOi8vcmVnaXN0cnkueWFybnBrZy5jb20vbm9kZS1mb3JnZS8tL25vZGUtZm9yZ2UtMC43LjYudGd6I2ZkZjNiNDE4YWVlMWY5NGYwZWY2NDJjZDYzNDg2Yzc3Y2E5NzI0YWMiCisgIGludGVncml0eSBzaGE1MTItc29sMzBMVXB6MWpRRkJqT0t3Ymp4aWppRTNiNnBqZDc0WXdmRDBmSk9LUGpGK2ZPTktiMllnOHJZZ1M2K2JLNlZEbCsvd2ZyNElZcEM3akR6TFVJZnc9PQogCiBzYW1sMi1qc0BeMS41LjA6Ci0gIHZlcnNpb24gIjEuNS4wIgotICByZXNvbHZlZCAiaHR0cHM6Ly9yZWdpc3RyeS55YXJucGtnLmNvbS9zYW1sMi1qcy8tL3NhbWwyLWpzLTEuNS4wLnRneiNjMGQyMjY4YTE3OWU3MzI5ZDI5ZWIyNWFhODJkZjU1MDM3NzRiMGQ5IgorICB2ZXJzaW9uICIxLjEyLjQiCisgIHJlc29sdmVkICJodHRwczovL3JlZ2lzdHJ5Lnlhcm5wa2cuY29tL3NhbWwyLWpzLy0vc2FtbDItanMtMS4xMi40LnRneiNjMjg4ZjIwYmRhNmQyYjkxMDczYjE2Yzk0ZWE3MmYyMjM0OWFjM2IzIgorICBpbnRlZ3JpdHkgc2hhMS13b2p5QzlwdEs1RUhPeGJKVHFjdklqU2F3N009CiAgIGRlcGVuZGVuY2llczoKLSAgICBhc3luYyAifjEuNS4yIgotICAgIGRlYnVnICJeMS4wLjQiCi0gICAgdW5kZXJzY29yZSAifjEuNi4wIgotICAgIHhtbC1jcnlwdG8gIl4wLjguMSIKLSAgICB4bWwtZW5jcnlwdGlvbiAifjAuNy40IgotICAgIHhtbDJqcyAifjAuNC4xIgotICAgIHhtbGJ1aWxkZXIgIn4yLjEuMCIKLSAgICB4bWxkb20gIn4wLjEuMTkiCisgICAgYXN5bmMgIl4yLjUuMCIKKyAgICBkZWJ1ZyAiXjIuNi4wIgorICAgIHVuZGVyc2NvcmUgIl4xLjguMCIKKyAgICB4bWwtY3J5cHRvICJeMC4xMC4wIgorICAgIHhtbC1lbmNyeXB0aW9uICJeMC4xMS4wIgorICAgIHhtbDJqcyAiXjAuNC4wIgorICAgIHhtbGJ1aWxkZXIgIn4yLjIuMCIKKyAgICB4bWxkb20gIl4wLjEuMCIKIAogc2F4QD49MC42LjA6CiAgIHZlcnNpb24gIjEuMi40IgogICByZXNvbHZlZCAiaHR0cHM6Ly9yZWdpc3RyeS55YXJucGtnLmNvbS9zYXgvLS9zYXgtMS4yLjQudGd6IzI4MTYyMzRlMjM3OGJkZGM0ZTUzNTRmYWI1Y2FhODk1ZGY3MTAwZDkiCisgIGludGVncml0eSBzaGE1MTItTnFWRHY5VHBBTlVqRm0wTjh1TTVHeEwzNlVnS2k5L2F0WncreDdZRm5ROGNrd0ZHS3JsNHhYNHlXdHJleTNVSm01blAxa1VibllnTG9wcVdOU1JoV3c9PQogCi11bmRlcnNjb3JlQD49MS41Lng6Cit1bmRlcnNjb3JlQF4xLjguMDoKICAgdmVyc2lvbiAiMS45LjEiCiAgIHJlc29sdmVkICJodHRwczovL3JlZ2lzdHJ5Lnlhcm5wa2cuY29tL3VuZGVyc2NvcmUvLS91bmRlcnNjb3JlLTEuOS4xLnRneiMwNmRjZTM0YTBlNjhhN2JhYmMyOWIzNjViOGU3NGI4OTI1MjAzOTYxIgorICBpbnRlZ3JpdHkgc2hhNTEyLTUvNGV0bkNrZDljOGd3Z293aTUvb20vbVlPNWFqQ2FPZ2R6ai9vVyswZVFWOVd4S0JEWnc1K3ljbUttZWFUWGpJblMvVzBCenBHTG8yeFIyYUJ3WmRnPT0KIAotdW5kZXJzY29yZUB+MS42LjA6Ci0gIHZlcnNpb24gIjEuNi4wIgotICByZXNvbHZlZCAiaHR0cHM6Ly9yZWdpc3RyeS55YXJucGtnLmNvbS91bmRlcnNjb3JlLy0vdW5kZXJzY29yZS0xLjYuMC50Z3ojOGIzOGIxMGNhY2RlZjYzMzM3YjhiMjRlNGZmODZkNDVhZWE1MjlhOCIKLQoteG1sLWNyeXB0b0BeMC44LjE6Ci0gIHZlcnNpb24gIjAuOC41IgotICByZXNvbHZlZCAiaHR0cDovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy94bWwtY3J5cHRvLy0veG1sLWNyeXB0by0wLjguNS50Z3ojMmJiY2ZiM2ViMzNmM2E4MmEyMThiODIyYmY2NzJiNmIxYzIwZTUzOCIKK3htbC1jcnlwdG9AXjAuMTAuMDoKKyAgdmVyc2lvbiAiMC4xMC4xIgorICByZXNvbHZlZCAiaHR0cHM6Ly9yZWdpc3RyeS55YXJucGtnLmNvbS94bWwtY3J5cHRvLy0veG1sLWNyeXB0by0wLjEwLjEudGd6I2Y4MzJmNzRjY2Y1NmYyNGFmY2FlMTE2M2ExZmNhYjQ0ZDk2Nzc0YTgiCisgIGludGVncml0eSBzaGExLStETDNUTTlXOGtyOHJoRmpvZnlyUk5sbmRLZz0KICAgZGVwZW5kZW5jaWVzOgogICAgIHhtbGRvbSAiPTAuMS4xOSIKICAgICB4cGF0aC5qcyAiPj0wLjAuMyIKIAoteG1sLWVuY3J5cHRpb25AfjAuNy40OgotICB2ZXJzaW9uICIwLjcuNCIKLSAgcmVzb2x2ZWQgImh0dHBzOi8vcmVnaXN0cnkueWFybnBrZy5jb20veG1sLWVuY3J5cHRpb24vLS94bWwtZW5jcnlwdGlvbi0wLjcuNC50Z3ojNDI3OTFlYzY0ZDU1NmQyNDU1ZGNiOWRhMGE1NDEyMzY2NWFjNjVjNyIKK3htbC1lbmNyeXB0aW9uQF4wLjExLjA6CisgIHZlcnNpb24gIjAuMTEuMiIKKyAgcmVzb2x2ZWQgImh0dHBzOi8vcmVnaXN0cnkueWFybnBrZy5jb20veG1sLWVuY3J5cHRpb24vLS94bWwtZW5jcnlwdGlvbi0wLjExLjIudGd6I2MyMTdmNTUwOTU0N2UzNGI1MDBiODI5ZjJjMGJjYTg1Y2NhNzNhMjEiCisgIGludGVncml0eSBzaGE1MTItalZ2RVM3aTVvdmRPN04rTmpnbmNBMzI2eFlLamhxZUFubnZJZ1JuWTdST0xDZkZxRURMd1AwU3hwLzMwU0hHMEFYUVYxMDQ4VDV5aW5PRnl2d0dGemc9PQogICBkZXBlbmRlbmNpZXM6Ci0gICAgYXN5bmMgIn4wLjIuNyIKLSAgICBlanMgIn4wLjguMyIKLSAgICBub2RlLWZvcmdlICIwLjIuMjQiCisgICAgYXN5bmMgIl4yLjEuNSIKKyAgICBlanMgIl4yLjUuNiIKKyAgICBub2RlLWZvcmdlICJeMC43LjAiCiAgICAgeG1sZG9tICJ+MC4xLjE1IgotICAgIHhwYXRoICIwLjAuNSIKKyAgICB4cGF0aCAiMC4wLjI3IgogCi14bWwyanNAfjAuNC4xOgoreG1sMmpzQF4wLjQuMDoKICAgdmVyc2lvbiAiMC40LjE5IgogICByZXNvbHZlZCAiaHR0cHM6Ly9yZWdpc3RyeS55YXJucGtnLmNvbS94bWwyanMvLS94bWwyanMtMC40LjE5LnRneiM2ODZjMjBmMjEzMjA5ZTk0YWJmMGQxYmNmMWVmYWEyOTFjNzgyN2E3IgorICBpbnRlZ3JpdHkgc2hhNTEyLWVzWm5KWkpPaUpSOXdXS015dXZTRTF5NkRxNUxDdUphbnFoeHNsSDJieE02ZHVhaE5aK0hNcENMaEJRR1prYlg2eFJmOHgxWTJlSmxndDJxM3FvNDlRPT0KICAgZGVwZW5kZW5jaWVzOgogICAgIHNheCAiPj0wLjYuMCIKICAgICB4bWxidWlsZGVyICJ+OS4wLjEiCiAKLXhtbGJ1aWxkZXJAfjIuMS4wOgotICB2ZXJzaW9uICIyLjEuMCIKLSAgcmVzb2x2ZWQgImh0dHA6Ly9yZWdpc3RyeS5ucG1qcy5vcmcveG1sYnVpbGRlci8tL3htbGJ1aWxkZXItMi4xLjAudGd6IzZkZGFlMzE2ODNiNmRmMTIxMDBiMjlmYzhhMGQ0ZjQ2MzQ5YWJiZWQiCit4bWxidWlsZGVyQH4yLjIuMDoKKyAgdmVyc2lvbiAiMi4yLjEiCisgIHJlc29sdmVkICJodHRwczovL3JlZ2lzdHJ5Lnlhcm5wa2cuY29tL3htbGJ1aWxkZXIvLS94bWxidWlsZGVyLTIuMi4xLnRneiM5MzI2NDMwZjEzMGQ4NzQzNWQ0YzQwODY2NDNhYTI5MjZlMTA1YTMyIgorICBpbnRlZ3JpdHkgc2hhMS1reVpERHhNTmgwTmRURUNHWkRxaWttNFFXakk9CiAgIGRlcGVuZGVuY2llczoKLSAgICB1bmRlcnNjb3JlICI+PTEuNS54IgorICAgIGxvZGFzaC1ub2RlICJ+Mi40LjEiCiAKIHhtbGJ1aWxkZXJAfjkuMC4xOgogICB2ZXJzaW9uICI5LjAuNyIKLSAgcmVzb2x2ZWQgImh0dHA6Ly9yZWdpc3RyeS5ucG1qcy5vcmcveG1sYnVpbGRlci8tL3htbGJ1aWxkZXItOS4wLjcudGd6IzEzMmVlNjNkMmVjNTU2NWM1NTdlMjBmNGMyMmRmOWFjYTY4NmIxMGQiCisgIHJlc29sdmVkICJodHRwczovL3JlZ2lzdHJ5Lnlhcm5wa2cuY29tL3htbGJ1aWxkZXIvLS94bWxidWlsZGVyLTkuMC43LnRneiMxMzJlZTYzZDJlYzU1NjVjNTU3ZTIwZjRjMjJkZjlhY2E2ODZiMTBkIgorICBpbnRlZ3JpdHkgc2hhMS1FeTdtUFM3RlZseFZmaUQwd2kzNXJLYUdzUTA9CiAKIHhtbGRvbUA9MC4xLjE5OgogICB2ZXJzaW9uICIwLjEuMTkiCiAgIHJlc29sdmVkICJodHRwczovL3JlZ2lzdHJ5Lnlhcm5wa2cuY29tL3htbGRvbS8tL3htbGRvbS0wLjEuMTkudGd6IzYzMWZjMDc3NzZlZmQ4NDExOGJmMjUxNzFiMzdlZDRkMDc1YTBhYmMiCisgIGludGVncml0eSBzaGExLVl4L0FkM2J2MkVFWXZ5VVhHemZ0VFFkYUNydz0KIAoteG1sZG9tQH4wLjEuMTUsIHhtbGRvbUB+MC4xLjE5OgoreG1sZG9tQF4wLjEuMCwgeG1sZG9tQH4wLjEuMTU6CiAgIHZlcnNpb24gIjAuMS4yNyIKICAgcmVzb2x2ZWQgImh0dHBzOi8vcmVnaXN0cnkueWFybnBrZy5jb20veG1sZG9tLy0veG1sZG9tLTAuMS4yNy50Z3ojZDUwMWY5N2IzYmRiNDAzYWY4ZWY5ZWNjMjA1NzMxODdhYWRhYzBlOSIKKyAgaW50ZWdyaXR5IHNoYTEtMVFINWV6dmJRRHI0NzU3TUlGY3hoNnJhd09rPQogCiB4cGF0aC5qc0A+PTAuMC4zOgogICB2ZXJzaW9uICIxLjEuMCIKICAgcmVzb2x2ZWQgImh0dHBzOi8vcmVnaXN0cnkueWFybnBrZy5jb20veHBhdGguanMvLS94cGF0aC5qcy0xLjEuMC50Z3ojMzgxNmE0NGVkNGJiMzUyMDkxMDgzZDAwMmEzODNkZDUxMDRhNWZmMSIKKyAgaW50ZWdyaXR5IHNoYTUxMi1qZytxa2ZTNEs4RTc5NjVzcWFVbDhtUm5nWGlLYjNXWkdmT05nRTE4cHIwM0ZVUWl1U1Y2RytFajR0UzU1QitySVFTRkVJdzNwaGRWQVE0cFBxTldmUT09CiAKLXhwYXRoQDAuMC41OgotICB2ZXJzaW9uICIwLjAuNSIKLSAgcmVzb2x2ZWQgImh0dHBzOi8vcmVnaXN0cnkueWFybnBrZy5jb20veHBhdGgvLS94cGF0aC0wLjAuNS50Z3ojNDU0MDM2ZjZlZjBmM2RmNWFmNWQ0YmE0YTExOWZiNzU2NzRiM2U2YyIKK3hwYXRoQDAuMC4yNzoKKyAgdmVyc2lvbiAiMC4wLjI3IgorICByZXNvbHZlZCAiaHR0cHM6Ly9yZWdpc3RyeS55YXJucGtnLmNvbS94cGF0aC8tL3hwYXRoLTAuMC4yNy50Z3ojZGQzNDIxZmJkY2M1NjQ2YWMzMmM0ODUzMWI0ZDdlOWQwYzJjZmE5MiIKKyAgaW50ZWdyaXR5IHNoYTUxMi1mZzAzV1J4dGtDVjZvaENsZVBOQUVDWXNtcEtLVHY1TDh5L1gzRG4xaFFyZWMzUE94MmpIWi8wUDJxUTZIdnNyVTFCbWVxWGNvZjNOR0d1ZUc2THh3UT09Cg==" - } - ] -} diff --git a/spec/fixtures/security-reports/remediations/remediation.patch b/spec/fixtures/security-reports/remediations/remediation.patch deleted file mode 100644 index bbfb6874627..00000000000 --- a/spec/fixtures/security-reports/remediations/remediation.patch +++ /dev/null @@ -1,180 +0,0 @@ -diff --git a/yarn.lock b/yarn.lock -index 0ecc92f..7fa4554 100644 ---- a/yarn.lock -+++ b/yarn.lock -@@ -2,103 +2,124 @@ - # yarn lockfile v1 - - --async@~0.2.7: -- version "0.2.10" -- resolved "http://registry.npmjs.org/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1" -- --async@~1.5.2: -- version "1.5.2" -- resolved "http://registry.npmjs.org/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" -+async@^2.1.5, async@^2.5.0: -+ version "2.6.1" -+ resolved "https://registry.yarnpkg.com/async/-/async-2.6.1.tgz#b245a23ca71930044ec53fa46aa00a3e87c6a610" -+ integrity sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ== -+ dependencies: -+ lodash "^4.17.10" - --debug@^1.0.4: -- version "1.0.5" -- resolved "https://registry.yarnpkg.com/debug/-/debug-1.0.5.tgz#f7241217430f99dec4c2b473eab92228e874c2ac" -+debug@^2.6.0: -+ version "2.6.9" -+ resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" -+ integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== - dependencies: - ms "2.0.0" - --ejs@~0.8.3: -- version "0.8.8" -- resolved "https://registry.yarnpkg.com/ejs/-/ejs-0.8.8.tgz#ffdc56dcc35d02926dd50ad13439bbc54061d598" -+ejs@^2.5.6: -+ version "2.6.1" -+ resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.6.1.tgz#498ec0d495655abc6f23cd61868d926464071aa0" -+ integrity sha512-0xy4A/twfrRCnkhfk8ErDi5DqdAsAqeGxht4xkCUrsvhhbQNs7E+4jV0CN7+NKIY0aHE72+XvqtBIXzD31ZbXQ== -+ -+lodash-node@~2.4.1: -+ version "2.4.1" -+ resolved "https://registry.yarnpkg.com/lodash-node/-/lodash-node-2.4.1.tgz#ea82f7b100c733d1a42af76801e506105e2a80ec" -+ integrity sha1-6oL3sQDHM9GkKvdoAeUGEF4qgOw= -+ -+lodash@^4.17.10: -+ version "4.17.11" -+ resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" -+ integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg== - - ms@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" -+ integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= - --node-forge@0.2.24: -- version "0.2.24" -- resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.2.24.tgz#fa6f846f42fa93f63a0a30c9fbff7b4e130e0858" -+node-forge@^0.7.0: -+ version "0.7.6" -+ resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.7.6.tgz#fdf3b418aee1f94f0ef642cd63486c77ca9724ac" -+ integrity sha512-sol30LUpz1jQFBjOKwbjxijiE3b6pjd74YwfD0fJOKPjF+fONKb2Yg8rYgS6+bK6VDl+/wfr4IYpC7jDzLUIfw== - - saml2-js@^1.5.0: -- version "1.5.0" -- resolved "https://registry.yarnpkg.com/saml2-js/-/saml2-js-1.5.0.tgz#c0d2268a179e7329d29eb25aa82df5503774b0d9" -+ version "1.12.4" -+ resolved "https://registry.yarnpkg.com/saml2-js/-/saml2-js-1.12.4.tgz#c288f20bda6d2b91073b16c94ea72f22349ac3b3" -+ integrity sha1-wojyC9ptK5EHOxbJTqcvIjSaw7M= - dependencies: -- async "~1.5.2" -- debug "^1.0.4" -- underscore "~1.6.0" -- xml-crypto "^0.8.1" -- xml-encryption "~0.7.4" -- xml2js "~0.4.1" -- xmlbuilder "~2.1.0" -- xmldom "~0.1.19" -+ async "^2.5.0" -+ debug "^2.6.0" -+ underscore "^1.8.0" -+ xml-crypto "^0.10.0" -+ xml-encryption "^0.11.0" -+ xml2js "^0.4.0" -+ xmlbuilder "~2.2.0" -+ xmldom "^0.1.0" - - sax@>=0.6.0: - version "1.2.4" - resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" -+ integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== - --underscore@>=1.5.x: -+underscore@^1.8.0: - version "1.9.1" - resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.9.1.tgz#06dce34a0e68a7babc29b365b8e74b8925203961" -+ integrity sha512-5/4etnCkd9c8gwgowi5/om/mYO5ajCaOgdzj/oW+0eQV9WxKBDZw5+ycmKmeaTXjInS/W0BzpGLo2xR2aBwZdg== - --underscore@~1.6.0: -- version "1.6.0" -- resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.6.0.tgz#8b38b10cacdef63337b8b24e4ff86d45aea529a8" -- --xml-crypto@^0.8.1: -- version "0.8.5" -- resolved "http://registry.npmjs.org/xml-crypto/-/xml-crypto-0.8.5.tgz#2bbcfb3eb33f3a82a218b822bf672b6b1c20e538" -+xml-crypto@^0.10.0: -+ version "0.10.1" -+ resolved "https://registry.yarnpkg.com/xml-crypto/-/xml-crypto-0.10.1.tgz#f832f74ccf56f24afcae1163a1fcab44d96774a8" -+ integrity sha1-+DL3TM9W8kr8rhFjofyrRNlndKg= - dependencies: - xmldom "=0.1.19" - xpath.js ">=0.0.3" - --xml-encryption@~0.7.4: -- version "0.7.4" -- resolved "https://registry.yarnpkg.com/xml-encryption/-/xml-encryption-0.7.4.tgz#42791ec64d556d2455dcb9da0a54123665ac65c7" -+xml-encryption@^0.11.0: -+ version "0.11.2" -+ resolved "https://registry.yarnpkg.com/xml-encryption/-/xml-encryption-0.11.2.tgz#c217f5509547e34b500b829f2c0bca85cca73a21" -+ integrity sha512-jVvES7i5ovdO7N+NjgncA326xYKjhqeAnnvIgRnY7ROLCfFqEDLwP0Sxp/30SHG0AXQV1048T5yinOFyvwGFzg== - dependencies: -- async "~0.2.7" -- ejs "~0.8.3" -- node-forge "0.2.24" -+ async "^2.1.5" -+ ejs "^2.5.6" -+ node-forge "^0.7.0" - xmldom "~0.1.15" -- xpath "0.0.5" -+ xpath "0.0.27" - --xml2js@~0.4.1: -+xml2js@^0.4.0: - version "0.4.19" - resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.19.tgz#686c20f213209e94abf0d1bcf1efaa291c7827a7" -+ integrity sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q== - dependencies: - sax ">=0.6.0" - xmlbuilder "~9.0.1" - --xmlbuilder@~2.1.0: -- version "2.1.0" -- resolved "http://registry.npmjs.org/xmlbuilder/-/xmlbuilder-2.1.0.tgz#6ddae31683b6df12100b29fc8a0d4f46349abbed" -+xmlbuilder@~2.2.0: -+ version "2.2.1" -+ resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-2.2.1.tgz#9326430f130d87435d4c4086643aa2926e105a32" -+ integrity sha1-kyZDDxMNh0NdTECGZDqikm4QWjI= - dependencies: -- underscore ">=1.5.x" -+ lodash-node "~2.4.1" - - xmlbuilder@~9.0.1: - version "9.0.7" -- resolved "http://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz#132ee63d2ec5565c557e20f4c22df9aca686b10d" -+ resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.7.tgz#132ee63d2ec5565c557e20f4c22df9aca686b10d" -+ integrity sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0= - - xmldom@=0.1.19: - version "0.1.19" - resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.1.19.tgz#631fc07776efd84118bf25171b37ed4d075a0abc" -+ integrity sha1-Yx/Ad3bv2EEYvyUXGzftTQdaCrw= - --xmldom@~0.1.15, xmldom@~0.1.19: -+xmldom@^0.1.0, xmldom@~0.1.15: - version "0.1.27" - resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.1.27.tgz#d501f97b3bdb403af8ef9ecc20573187aadac0e9" -+ integrity sha1-1QH5ezvbQDr4757MIFcxh6rawOk= - - xpath.js@>=0.0.3: - version "1.1.0" - resolved "https://registry.yarnpkg.com/xpath.js/-/xpath.js-1.1.0.tgz#3816a44ed4bb352091083d002a383dd5104a5ff1" -+ integrity sha512-jg+qkfS4K8E7965sqaUl8mRngXiKb3WZGfONgE18pr03FUQiuSV6G+Ej4tS55B+rIQSFEIw3phdVAQ4pPqNWfQ== - --xpath@0.0.5: -- version "0.0.5" -- resolved "https://registry.yarnpkg.com/xpath/-/xpath-0.0.5.tgz#454036f6ef0f3df5af5d4ba4a119fb75674b3e6c" -+xpath@0.0.27: -+ version "0.0.27" -+ resolved "https://registry.yarnpkg.com/xpath/-/xpath-0.0.27.tgz#dd3421fbdcc5646ac32c48531b4d7e9d0c2cfa92" -+ integrity sha512-fg03WRxtkCV6ohClePNAECYsmpKKTv5L8y/X3Dn1hQrec3POx2jHZ/0P2qQ6HvsrU1BmeqXcof3NGGueG6LxwQ== diff --git a/spec/fixtures/security-reports/remediations/yarn.lock b/spec/fixtures/security-reports/remediations/yarn.lock deleted file mode 100644 index 0ecc92fb711..00000000000 --- a/spec/fixtures/security-reports/remediations/yarn.lock +++ /dev/null @@ -1,104 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -async@~0.2.7: - version "0.2.10" - resolved "http://registry.npmjs.org/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1" - -async@~1.5.2: - version "1.5.2" - resolved "http://registry.npmjs.org/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" - -debug@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/debug/-/debug-1.0.5.tgz#f7241217430f99dec4c2b473eab92228e874c2ac" - dependencies: - ms "2.0.0" - -ejs@~0.8.3: - version "0.8.8" - resolved "https://registry.yarnpkg.com/ejs/-/ejs-0.8.8.tgz#ffdc56dcc35d02926dd50ad13439bbc54061d598" - -ms@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - -node-forge@0.2.24: - version "0.2.24" - resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.2.24.tgz#fa6f846f42fa93f63a0a30c9fbff7b4e130e0858" - -saml2-js@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/saml2-js/-/saml2-js-1.5.0.tgz#c0d2268a179e7329d29eb25aa82df5503774b0d9" - dependencies: - async "~1.5.2" - debug "^1.0.4" - underscore "~1.6.0" - xml-crypto "^0.8.1" - xml-encryption "~0.7.4" - xml2js "~0.4.1" - xmlbuilder "~2.1.0" - xmldom "~0.1.19" - -sax@>=0.6.0: - version "1.2.4" - resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" - -underscore@>=1.5.x: - version "1.9.1" - resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.9.1.tgz#06dce34a0e68a7babc29b365b8e74b8925203961" - -underscore@~1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.6.0.tgz#8b38b10cacdef63337b8b24e4ff86d45aea529a8" - -xml-crypto@^0.8.1: - version "0.8.5" - resolved "http://registry.npmjs.org/xml-crypto/-/xml-crypto-0.8.5.tgz#2bbcfb3eb33f3a82a218b822bf672b6b1c20e538" - dependencies: - xmldom "=0.1.19" - xpath.js ">=0.0.3" - -xml-encryption@~0.7.4: - version "0.7.4" - resolved "https://registry.yarnpkg.com/xml-encryption/-/xml-encryption-0.7.4.tgz#42791ec64d556d2455dcb9da0a54123665ac65c7" - dependencies: - async "~0.2.7" - ejs "~0.8.3" - node-forge "0.2.24" - xmldom "~0.1.15" - xpath "0.0.5" - -xml2js@~0.4.1: - version "0.4.19" - resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.19.tgz#686c20f213209e94abf0d1bcf1efaa291c7827a7" - dependencies: - sax ">=0.6.0" - xmlbuilder "~9.0.1" - -xmlbuilder@~2.1.0: - version "2.1.0" - resolved "http://registry.npmjs.org/xmlbuilder/-/xmlbuilder-2.1.0.tgz#6ddae31683b6df12100b29fc8a0d4f46349abbed" - dependencies: - underscore ">=1.5.x" - -xmlbuilder@~9.0.1: - version "9.0.7" - resolved "http://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz#132ee63d2ec5565c557e20f4c22df9aca686b10d" - -xmldom@=0.1.19: - version "0.1.19" - resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.1.19.tgz#631fc07776efd84118bf25171b37ed4d075a0abc" - -xmldom@~0.1.15, xmldom@~0.1.19: - version "0.1.27" - resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.1.27.tgz#d501f97b3bdb403af8ef9ecc20573187aadac0e9" - -xpath.js@>=0.0.3: - version "1.1.0" - resolved "https://registry.yarnpkg.com/xpath.js/-/xpath.js-1.1.0.tgz#3816a44ed4bb352091083d002a383dd5104a5ff1" - -xpath@0.0.5: - version "0.0.5" - resolved "https://registry.yarnpkg.com/xpath/-/xpath-0.0.5.tgz#454036f6ef0f3df5af5d4ba4a119fb75674b3e6c" diff --git a/spec/frontend/lib/utils/url_utility_spec.js b/spec/frontend/lib/utils/url_utility_spec.js index a986bc49f28..b0bdd924921 100644 --- a/spec/frontend/lib/utils/url_utility_spec.js +++ b/spec/frontend/lib/utils/url_utility_spec.js @@ -94,6 +94,12 @@ describe('URL utility', () => { it('adds and updates encoded params', () => { expect(urlUtils.mergeUrlParams({ a: '&', q: '?' }, '?a=%23#frag')).toBe('?a=%26&q=%3F#frag'); }); + + it('treats "+" as "%20"', () => { + expect(urlUtils.mergeUrlParams({ ref: 'bogus' }, '?a=lorem+ipsum&ref=charlie')).toBe( + '?a=lorem%20ipsum&ref=bogus', + ); + }); }); describe('removeParams', () => { diff --git a/spec/frontend/mocks/mocks_helper_spec.js b/spec/frontend/mocks/mocks_helper_spec.js index 34be110a7e3..b8bb02c2f43 100644 --- a/spec/frontend/mocks/mocks_helper_spec.js +++ b/spec/frontend/mocks/mocks_helper_spec.js @@ -46,7 +46,9 @@ describe('mocks_helper.js', () => { readdir.sync.mockReturnValue([]); setupManualMocks(); - readdir.mock.calls.forEach(call => { + const readdirSpy = readdir.sync; + expect(readdirSpy).toHaveBeenCalled(); + readdirSpy.mock.calls.forEach(call => { expect(call[1].deep).toBeLessThan(100); }); }); diff --git a/spec/javascripts/monitoring/dashboard_spec.js b/spec/javascripts/monitoring/dashboard_spec.js index 624d8b14c8f..02c3f303912 100644 --- a/spec/javascripts/monitoring/dashboard_spec.js +++ b/spec/javascripts/monitoring/dashboard_spec.js @@ -414,6 +414,26 @@ describe('Dashboard', () => { expect(clipboardText()).toContain(`y_label=`); }); + it('undefined parameter is stripped', done => { + wrapper.setProps({ currentDashboard: undefined }); + + wrapper.vm.$nextTick(() => { + expect(clipboardText()).not.toContain(`dashboard=`); + expect(clipboardText()).toContain(`y_label=`); + done(); + }); + }); + + it('null parameter is stripped', done => { + wrapper.setProps({ currentDashboard: null }); + + wrapper.vm.$nextTick(() => { + expect(clipboardText()).not.toContain(`dashboard=`); + expect(clipboardText()).toContain(`y_label=`); + done(); + }); + }); + it('creates a toast when clicked', () => { spyOn(wrapper.vm.$toast, 'show').and.stub(); diff --git a/spec/javascripts/vue_shared/directives/autofocusonshow_spec.js b/spec/javascripts/vue_shared/directives/autofocusonshow_spec.js new file mode 100644 index 00000000000..f1ca5f61496 --- /dev/null +++ b/spec/javascripts/vue_shared/directives/autofocusonshow_spec.js @@ -0,0 +1,38 @@ +import autofocusonshow from '~/vue_shared/directives/autofocusonshow'; + +/** + * We're testing this directive's hooks as pure functions + * since behaviour of this directive is highly-dependent + * on underlying DOM methods. + */ +describe('AutofocusOnShow directive', () => { + describe('with input invisible on component render', () => { + let el; + + beforeAll(() => { + setFixtures('<div id="container" style="display: none;"><input id="inputel"/></div>'); + el = document.querySelector('#inputel'); + }); + + it('should bind IntersectionObserver on input element', () => { + spyOn(el, 'focus'); + + autofocusonshow.inserted(el); + + expect(el.visibilityObserver).toBeDefined(); + expect(el.focus).not.toHaveBeenCalled(); + }); + + it('should stop IntersectionObserver on input element on unbind hook', () => { + el.visibilityObserver = { + disconnect: () => {}, + }; + spyOn(el.visibilityObserver, 'disconnect'); + + autofocusonshow.unbind(el); + + expect(el.visibilityObserver).toBeDefined(); + expect(el.visibilityObserver.disconnect).toHaveBeenCalled(); + }); + }); +}); diff --git a/spec/lib/gitlab/action_rate_limiter_spec.rb b/spec/lib/gitlab/action_rate_limiter_spec.rb index 8dbad32dfb4..8b510a475d2 100644 --- a/spec/lib/gitlab/action_rate_limiter_spec.rb +++ b/spec/lib/gitlab/action_rate_limiter_spec.rb @@ -74,9 +74,9 @@ describe Gitlab::ActionRateLimiter, :clean_gitlab_redis_cache do { message: 'Action_Rate_Limiter_Request', env: type, - ip: '127.0.0.1', + remote_ip: '127.0.0.1', request_method: 'GET', - fullpath: fullpath + path: fullpath } end diff --git a/spec/lib/gitlab/ci/build/policy/variables_spec.rb b/spec/lib/gitlab/ci/build/policy/variables_spec.rb index f712f47a558..7140c14facb 100644 --- a/spec/lib/gitlab/ci/build/policy/variables_spec.rb +++ b/spec/lib/gitlab/ci/build/policy/variables_spec.rb @@ -13,7 +13,12 @@ describe Gitlab::Ci::Build::Policy::Variables do build(:ci_build, pipeline: pipeline, project: project, ref: 'master') end - let(:seed) { double('build seed', to_resource: ci_build) } + let(:seed) do + double('build seed', + to_resource: ci_build, + scoped_variables_hash: ci_build.scoped_variables_hash + ) + end before do pipeline.variables.build(key: 'CI_PROJECT_NAME', value: '') @@ -83,7 +88,12 @@ describe Gitlab::Ci::Build::Policy::Variables do build(:ci_bridge, pipeline: pipeline, project: project, ref: 'master') end - let(:seed) { double('bridge seed', to_resource: bridge) } + let(:seed) do + double('bridge seed', + to_resource: bridge, + scoped_variables_hash: ci_build.scoped_variables_hash + ) + end it 'is satisfied by a matching expression for a bridge job' do policy = described_class.new(['$MY_VARIABLE']) diff --git a/spec/lib/gitlab/ci/build/rules/rule_spec.rb b/spec/lib/gitlab/ci/build/rules/rule_spec.rb new file mode 100644 index 00000000000..99852bd4228 --- /dev/null +++ b/spec/lib/gitlab/ci/build/rules/rule_spec.rb @@ -0,0 +1,50 @@ +require 'spec_helper' + +describe Gitlab::Ci::Build::Rules::Rule do + let(:seed) do + double('build seed', + to_resource: ci_build, + scoped_variables_hash: ci_build.scoped_variables_hash + ) + end + + let(:pipeline) { create(:ci_pipeline) } + let(:ci_build) { build(:ci_build, pipeline: pipeline) } + let(:rule) { described_class.new(rule_hash) } + + describe '#matches?' do + subject { rule.matches?(pipeline, seed) } + + context 'with one matching clause' do + let(:rule_hash) do + { if: '$VAR == null', when: 'always' } + end + + it { is_expected.to eq(true) } + end + + context 'with two matching clauses' do + let(:rule_hash) do + { if: '$VAR == null', changes: '**/*', when: 'always' } + end + + it { is_expected.to eq(true) } + end + + context 'with a matching and non-matching clause' do + let(:rule_hash) do + { if: '$VAR != null', changes: '$VAR == null', when: 'always' } + end + + it { is_expected.to eq(false) } + end + + context 'with two non-matching clauses' do + let(:rule_hash) do + { if: '$VAR != null', changes: 'README', when: 'always' } + end + + it { is_expected.to eq(false) } + end + end +end diff --git a/spec/lib/gitlab/ci/build/rules_spec.rb b/spec/lib/gitlab/ci/build/rules_spec.rb new file mode 100644 index 00000000000..d7793ebc806 --- /dev/null +++ b/spec/lib/gitlab/ci/build/rules_spec.rb @@ -0,0 +1,168 @@ +require 'spec_helper' + +describe Gitlab::Ci::Build::Rules do + let(:pipeline) { create(:ci_pipeline) } + let(:ci_build) { build(:ci_build, pipeline: pipeline) } + + let(:seed) do + double('build seed', + to_resource: ci_build, + scoped_variables_hash: ci_build.scoped_variables_hash + ) + end + + let(:rules) { described_class.new(rule_list) } + + describe '.new' do + let(:rules_ivar) { rules.instance_variable_get :@rule_list } + let(:default_when) { rules.instance_variable_get :@default_when } + + context 'with no rules' do + let(:rule_list) { [] } + + it 'sets @rule_list to an empty array' do + expect(rules_ivar).to eq([]) + end + + it 'sets @default_when to "on_success"' do + expect(default_when).to eq('on_success') + end + end + + context 'with one rule' do + let(:rule_list) { [{ if: '$VAR == null', when: 'always' }] } + + it 'sets @rule_list to an array of a single rule' do + expect(rules_ivar).to be_an(Array) + end + + it 'sets @default_when to "on_success"' do + expect(default_when).to eq('on_success') + end + end + + context 'with multiple rules' do + let(:rule_list) do + [ + { if: '$VAR == null', when: 'always' }, + { if: '$VAR == null', when: 'always' } + ] + end + + it 'sets @rule_list to an array of a single rule' do + expect(rules_ivar).to be_an(Array) + end + + it 'sets @default_when to "on_success"' do + expect(default_when).to eq('on_success') + end + end + + context 'with a specified default when:' do + let(:rule_list) { [{ if: '$VAR == null', when: 'always' }] } + let(:rules) { described_class.new(rule_list, 'manual') } + + it 'sets @rule_list to an array of a single rule' do + expect(rules_ivar).to be_an(Array) + end + + it 'sets @default_when to "manual"' do + expect(default_when).to eq('manual') + end + end + end + + describe '#evaluate' do + subject { rules.evaluate(pipeline, seed) } + + context 'with nil rules' do + let(:rule_list) { nil } + + it { is_expected.to eq(described_class::Result.new('on_success')) } + + context 'and when:manual set as the default' do + let(:rules) { described_class.new(rule_list, 'manual') } + + it { is_expected.to eq(described_class::Result.new('manual')) } + end + end + + context 'with no rules' do + let(:rule_list) { [] } + + it { is_expected.to eq(described_class::Result.new('never')) } + + context 'and when:manual set as the default' do + let(:rules) { described_class.new(rule_list, 'manual') } + + it { is_expected.to eq(described_class::Result.new('never')) } + end + end + + context 'with one rule without any clauses' do + let(:rule_list) { [{ when: 'manual' }] } + + it { is_expected.to eq(described_class::Result.new('manual')) } + end + + context 'with one matching rule' do + let(:rule_list) { [{ if: '$VAR == null', when: 'always' }] } + + it { is_expected.to eq(described_class::Result.new('always')) } + end + + context 'with two matching rules' do + let(:rule_list) do + [ + { if: '$VAR == null', when: 'delayed', start_in: '1 day' }, + { if: '$VAR == null', when: 'always' } + ] + end + + it 'returns the value of the first matched rule in the list' do + expect(subject).to eq(described_class::Result.new('delayed', '1 day')) + end + end + + context 'with a non-matching and matching rule' do + let(:rule_list) do + [ + { if: '$VAR =! null', when: 'delayed', start_in: '1 day' }, + { if: '$VAR == null', when: 'always' } + ] + end + + it { is_expected.to eq(described_class::Result.new('always')) } + end + + context 'with a matching and non-matching rule' do + let(:rule_list) do + [ + { if: '$VAR == null', when: 'delayed', start_in: '1 day' }, + { if: '$VAR != null', when: 'always' } + ] + end + + it { is_expected.to eq(described_class::Result.new('delayed', '1 day')) } + end + + context 'with non-matching rules' do + let(:rule_list) do + [ + { if: '$VAR != null', when: 'delayed', start_in: '1 day' }, + { if: '$VAR != null', when: 'always' } + ] + end + + it { is_expected.to eq(described_class::Result.new('never')) } + + context 'and when:manual set as the default' do + let(:rules) { described_class.new(rule_list, 'manual') } + + it 'does not return the default when:' do + expect(subject).to eq(described_class::Result.new('never')) + end + end + end + end +end diff --git a/spec/lib/gitlab/ci/config/entry/job_spec.rb b/spec/lib/gitlab/ci/config/entry/job_spec.rb index 415ade7a096..1853efde350 100644 --- a/spec/lib/gitlab/ci/config/entry/job_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/job_spec.rb @@ -11,7 +11,7 @@ describe Gitlab::Ci::Config::Entry::Job do let(:result) do %i[before_script script stage type after_script cache - image services only except variables artifacts + image services only except rules variables artifacts environment coverage retry] end @@ -201,6 +201,21 @@ describe Gitlab::Ci::Config::Entry::Job do expect(entry.errors).to include 'job parallel must be an integer' end end + + context 'when it uses both "when:" and "rules:"' do + let(:config) do + { + script: 'echo', + when: 'on_failure', + rules: [{ if: '$VARIABLE', when: 'on_success' }] + } + end + + it 'returns an error about when: being combined with rules' do + expect(entry).not_to be_valid + expect(entry.errors).to include 'job config key may not be used with `rules`: when' + end + end end context 'when delayed job' do @@ -240,6 +255,100 @@ describe Gitlab::Ci::Config::Entry::Job do end end + context 'when only: is used with rules:' do + let(:config) { { only: ['merge_requests'], rules: [{ if: '$THIS' }] } } + + it 'returns error about mixing only: with rules:' do + expect(entry).not_to be_valid + expect(entry.errors).to include /may not be used with `rules`/ + end + + context 'and only: is blank' do + let(:config) { { only: nil, rules: [{ if: '$THIS' }] } } + + it 'returns error about mixing only: with rules:' do + expect(entry).not_to be_valid + expect(entry.errors).to include /may not be used with `rules`/ + end + end + + context 'and rules: is blank' do + let(:config) { { only: ['merge_requests'], rules: nil } } + + it 'returns error about mixing only: with rules:' do + expect(entry).not_to be_valid + expect(entry.errors).to include /may not be used with `rules`/ + end + end + end + + context 'when except: is used with rules:' do + let(:config) { { except: { refs: %w[master] }, rules: [{ if: '$THIS' }] } } + + it 'returns error about mixing except: with rules:' do + expect(entry).not_to be_valid + expect(entry.errors).to include /may not be used with `rules`/ + end + + context 'and except: is blank' do + let(:config) { { except: nil, rules: [{ if: '$THIS' }] } } + + it 'returns error about mixing except: with rules:' do + expect(entry).not_to be_valid + expect(entry.errors).to include /may not be used with `rules`/ + end + end + + context 'and rules: is blank' do + let(:config) { { except: { refs: %w[master] }, rules: nil } } + + it 'returns error about mixing except: with rules:' do + expect(entry).not_to be_valid + expect(entry.errors).to include /may not be used with `rules`/ + end + end + end + + context 'when only: and except: are both used with rules:' do + let(:config) do + { + only: %w[merge_requests], + except: { refs: %w[master] }, + rules: [{ if: '$THIS' }] + } + end + + it 'returns errors about mixing both only: and except: with rules:' do + expect(entry).not_to be_valid + expect(entry.errors).to include /may not be used with `rules`/ + expect(entry.errors).to include /may not be used with `rules`/ + end + + context 'when only: and except: as both blank' do + let(:config) do + { only: nil, except: nil, rules: [{ if: '$THIS' }] } + end + + it 'returns errors about mixing both only: and except: with rules:' do + expect(entry).not_to be_valid + expect(entry.errors).to include /may not be used with `rules`/ + expect(entry.errors).to include /may not be used with `rules`/ + end + end + + context 'when rules: is blank' do + let(:config) do + { only: %w[merge_requests], except: { refs: %w[master] }, rules: nil } + end + + it 'returns errors about mixing both only: and except: with rules:' do + expect(entry).not_to be_valid + expect(entry.errors).to include /may not be used with `rules`/ + expect(entry.errors).to include /may not be used with `rules`/ + end + end + end + context 'when start_in specified without delayed specification' do let(:config) { { start_in: '1 day' } } diff --git a/spec/lib/gitlab/ci/config/entry/policy_spec.rb b/spec/lib/gitlab/ci/config/entry/policy_spec.rb index 266a27c1e47..a606eb303e7 100644 --- a/spec/lib/gitlab/ci/config/entry/policy_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/policy_spec.rb @@ -51,8 +51,6 @@ describe Gitlab::Ci::Config::Entry::Policy do let(:config) { ['/^(?!master).+/'] } - subject { described_class.new([regexp]) } - context 'when allow_unsafe_ruby_regexp is disabled' do before do stub_feature_flags(allow_unsafe_ruby_regexp: false) @@ -113,8 +111,6 @@ describe Gitlab::Ci::Config::Entry::Policy do let(:config) { { refs: ['/^(?!master).+/'] } } - subject { described_class.new([regexp]) } - context 'when allow_unsafe_ruby_regexp is disabled' do before do stub_feature_flags(allow_unsafe_ruby_regexp: false) @@ -204,6 +200,14 @@ describe Gitlab::Ci::Config::Entry::Policy do end context 'when changes policy is invalid' do + let(:config) { { changes: 'some/*' } } + + it 'returns errors' do + expect(entry.errors).to include /changes should be an array of strings/ + end + end + + context 'when changes policy is invalid' do let(:config) { { changes: [1, 2] } } it 'returns errors' do diff --git a/spec/lib/gitlab/ci/config/entry/rules/rule_spec.rb b/spec/lib/gitlab/ci/config/entry/rules/rule_spec.rb new file mode 100644 index 00000000000..c25344ec1a4 --- /dev/null +++ b/spec/lib/gitlab/ci/config/entry/rules/rule_spec.rb @@ -0,0 +1,208 @@ +require 'fast_spec_helper' +require 'chronic_duration' +require 'support/helpers/stub_feature_flags' +require_dependency 'active_model' + +describe Gitlab::Ci::Config::Entry::Rules::Rule do + let(:entry) { described_class.new(config) } + + describe '.new' do + subject { entry } + + context 'with a when: value but no clauses' do + let(:config) { { when: 'manual' } } + + it { is_expected.to be_valid } + end + + context 'when specifying an if: clause' do + let(:config) { { if: '$THIS || $THAT', when: 'manual' } } + + it { is_expected.to be_valid } + + describe '#when' do + subject { entry.when } + + it { is_expected.to eq('manual') } + end + end + + context 'using a list of multiple expressions' do + let(:config) { { if: ['$MY_VAR == "this"', '$YOUR_VAR == "that"'] } } + + it { is_expected.not_to be_valid } + + it 'reports an error about invalid format' do + expect(subject.errors).to include(/invalid expression syntax/) + end + end + + context 'when specifying an invalid if: clause expression' do + let(:config) { { if: ['$MY_VAR =='] } } + + it { is_expected.not_to be_valid } + + it 'reports an error about invalid statement' do + expect(subject.errors).to include(/invalid expression syntax/) + end + end + + context 'when specifying an if: clause expression with an invalid token' do + let(:config) { { if: ['$MY_VAR == 123'] } } + + it { is_expected.not_to be_valid } + + it 'reports an error about invalid statement' do + expect(subject.errors).to include(/invalid expression syntax/) + end + end + + context 'when using invalid regex in an if: clause' do + let(:config) { { if: ['$MY_VAR =~ /some ( thing/'] } } + + it 'reports an error about invalid expression' do + expect(subject.errors).to include(/invalid expression syntax/) + end + end + + context 'when using an if: clause with lookahead regex character "?"' do + let(:config) { { if: '$CI_COMMIT_REF =~ /^(?!master).+/' } } + + context 'when allow_unsafe_ruby_regexp is disabled' do + it { is_expected.not_to be_valid } + + it 'reports an error about invalid expression syntax' do + expect(subject.errors).to include(/invalid expression syntax/) + end + end + end + + context 'when using a changes: clause' do + let(:config) { { changes: %w[app/ lib/ spec/ other/* paths/**/*.rb] } } + + it { is_expected.to be_valid } + end + + context 'when using a string as an invalid changes: clause' do + let(:config) { { changes: 'a regular string' } } + + it { is_expected.not_to be_valid } + + it 'reports an error about invalid policy' do + expect(subject.errors).to include(/should be an array of strings/) + end + end + + context 'when using a list as an invalid changes: clause' do + let(:config) { { changes: [1, 2] } } + + it { is_expected.not_to be_valid } + + it 'returns errors' do + expect(subject.errors).to include(/changes should be an array of strings/) + end + end + + context 'specifying a delayed job' do + let(:config) { { if: '$THIS || $THAT', when: 'delayed', start_in: '15 minutes' } } + + it { is_expected.to be_valid } + + it 'sets attributes for the job delay' do + expect(entry.when).to eq('delayed') + expect(entry.start_in).to eq('15 minutes') + end + + context 'without a when: key' do + let(:config) { { if: '$THIS || $THAT', start_in: '15 minutes' } } + + it { is_expected.not_to be_valid } + + it 'returns an error about the disallowed key' do + expect(entry.errors).to include(/disallowed keys: start_in/) + end + end + + context 'without a start_in: key' do + let(:config) { { if: '$THIS || $THAT', when: 'delayed' } } + + it { is_expected.not_to be_valid } + + it 'returns an error about tstart_in being blank' do + expect(entry.errors).to include(/start in can't be blank/) + end + end + end + + context 'when specifying unknown policy' do + let(:config) { { invalid: :something } } + + it { is_expected.not_to be_valid } + + it 'returns error about invalid key' do + expect(entry.errors).to include(/unknown keys: invalid/) + end + end + + context 'when clause is empty' do + let(:config) { {} } + + it { is_expected.not_to be_valid } + + it 'is not a valid configuration' do + expect(entry.errors).to include(/can't be blank/) + end + end + + context 'when policy strategy does not match' do + let(:config) { 'string strategy' } + + it { is_expected.not_to be_valid } + + it 'returns information about errors' do + expect(entry.errors) + .to include(/should be a hash/) + end + end + end + + describe '#value' do + subject { entry.value } + + context 'when specifying an if: clause' do + let(:config) { { if: '$THIS || $THAT', when: 'manual' } } + + it 'stores the expression as "if"' do + expect(subject).to eq(if: '$THIS || $THAT', when: 'manual') + end + end + + context 'when using a changes: clause' do + let(:config) { { changes: %w[app/ lib/ spec/ other/* paths/**/*.rb] } } + + it { is_expected.to eq(config) } + end + + context 'when default value has been provided' do + let(:config) { { changes: %w[app/**/*.rb] } } + + before do + entry.default = { changes: %w[**/*] } + end + + it 'does not set a default value' do + expect(entry.default).to eq(nil) + end + + it 'does not add to provided configuration' do + expect(entry.value).to eq(config) + end + end + end + + describe '.default' do + it 'does not have default value' do + expect(described_class.default).to be_nil + end + end +end diff --git a/spec/lib/gitlab/ci/config/entry/rules_spec.rb b/spec/lib/gitlab/ci/config/entry/rules_spec.rb new file mode 100644 index 00000000000..291e7373daf --- /dev/null +++ b/spec/lib/gitlab/ci/config/entry/rules_spec.rb @@ -0,0 +1,135 @@ +require 'fast_spec_helper' +require 'support/helpers/stub_feature_flags' +require_dependency 'active_model' + +describe Gitlab::Ci::Config::Entry::Rules do + let(:entry) { described_class.new(config) } + + describe '.new' do + subject { entry } + + context 'with a list of rule rule' do + let(:config) do + [{ if: '$THIS == "that"', when: 'never' }] + end + + it { is_expected.to be_a(described_class) } + it { is_expected.to be_valid } + + context 'after #compose!' do + before do + subject.compose! + end + + it { is_expected.to be_valid } + end + end + + context 'with a list of two rules' do + let(:config) do + [ + { if: '$THIS == "that"', when: 'always' }, + { if: '$SKIP', when: 'never' } + ] + end + + it { is_expected.to be_a(described_class) } + it { is_expected.to be_valid } + + context 'after #compose!' do + before do + subject.compose! + end + + it { is_expected.to be_valid } + end + end + + context 'with a single rule object' do + let(:config) do + { if: '$SKIP', when: 'never' } + end + + it { is_expected.not_to be_valid } + end + + context 'with an invalid boolean when:' do + let(:config) do + [{ if: '$THIS == "that"', when: false }] + end + + it { is_expected.to be_a(described_class) } + it { is_expected.to be_valid } + + context 'after #compose!' do + before do + subject.compose! + end + + it { is_expected.not_to be_valid } + + it 'returns an error about invalid when:' do + expect(subject.errors).to include(/when unknown value: false/) + end + end + end + + context 'with an invalid string when:' do + let(:config) do + [{ if: '$THIS == "that"', when: 'explode' }] + end + + it { is_expected.to be_a(described_class) } + it { is_expected.to be_valid } + + context 'after #compose!' do + before do + subject.compose! + end + + it { is_expected.not_to be_valid } + + it 'returns an error about invalid when:' do + expect(subject.errors).to include(/when unknown value: explode/) + end + end + end + end + + describe '#value' do + subject { entry.value } + + context 'with a list of rule rule' do + let(:config) do + [{ if: '$THIS == "that"', when: 'never' }] + end + + it { is_expected.to eq(config) } + end + + context 'with a list of two rules' do + let(:config) do + [ + { if: '$THIS == "that"', when: 'always' }, + { if: '$SKIP', when: 'never' } + ] + end + + it { is_expected.to eq(config) } + end + + context 'with a single rule object' do + let(:config) do + { if: '$SKIP', when: 'never' } + end + + it { is_expected.to eq(config) } + end + end + + describe '.default' do + it 'does not have default policy' do + expect(described_class.default).to be_nil + end + end +end diff --git a/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb b/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb index 1a9350d68bd..89431b80be3 100644 --- a/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb @@ -15,6 +15,60 @@ describe Gitlab::Ci::Pipeline::Seed::Build do it { is_expected.to be_a(Hash) } it { is_expected.to include(:name, :project, :ref) } + + context 'with job:when' do + let(:attributes) { { name: 'rspec', ref: 'master', when: 'on_failure' } } + + it { is_expected.to include(when: 'on_failure') } + end + + context 'with job:when:delayed' do + let(:attributes) { { name: 'rspec', ref: 'master', when: 'delayed', start_in: '3 hours' } } + + it { is_expected.to include(when: 'delayed', start_in: '3 hours') } + end + + context 'with job:rules:[when:]' do + context 'is matched' do + let(:attributes) { { name: 'rspec', ref: 'master', rules: [{ if: '$VAR == null', when: 'always' }] } } + + it { is_expected.to include(when: 'always') } + end + + context 'is not matched' do + let(:attributes) { { name: 'rspec', ref: 'master', rules: [{ if: '$VAR != null', when: 'always' }] } } + + it { is_expected.to include(when: 'never') } + end + end + + context 'with job:rules:[when:delayed]' do + context 'is matched' do + let(:attributes) { { name: 'rspec', ref: 'master', rules: [{ if: '$VAR == null', when: 'delayed', start_in: '3 hours' }] } } + + it { is_expected.to include(when: 'delayed', start_in: '3 hours') } + end + + context 'is not matched' do + let(:attributes) { { name: 'rspec', ref: 'master', rules: [{ if: '$VAR != null', when: 'delayed', start_in: '3 hours' }] } } + + it { is_expected.to include(when: 'never') } + end + end + + context 'with job:rules but no explicit when:' do + context 'is matched' do + let(:attributes) { { name: 'rspec', ref: 'master', rules: [{ if: '$VAR == null' }] } } + + it { is_expected.to include(when: 'on_success') } + end + + context 'is not matched' do + let(:attributes) { { name: 'rspec', ref: 'master', rules: [{ if: '$VAR != null' }] } } + + it { is_expected.to include(when: 'never') } + end + end end describe '#bridge?' do @@ -366,9 +420,25 @@ describe Gitlab::Ci::Pipeline::Seed::Build do it { is_expected.not_to be_included } end + + context 'when using both only and except policies' do + let(:attributes) do + { + name: 'rspec', + only: { + refs: ["branches@#{pipeline.project_full_path}"] + }, + except: { + refs: ["branches@#{pipeline.project_full_path}"] + } + } + end + + it { is_expected.not_to be_included } + end end - context 'when repository path does not matches' do + context 'when repository path does not match' do context 'when using only' do let(:attributes) do { name: 'rspec', only: { refs: %w[branches@fork] } } @@ -397,6 +467,215 @@ describe Gitlab::Ci::Pipeline::Seed::Build do it { is_expected.not_to be_included } end end + + context 'using rules:' do + using RSpec::Parameterized + + let(:attributes) { { name: 'rspec', rules: rule_set } } + + context 'with a matching if: rule' do + context 'with an explicit `when: never`' do + where(:rule_set) do + [ + [[{ if: '$VARIABLE == null', when: 'never' }]], + [[{ if: '$VARIABLE == null', when: 'never' }, { if: '$VARIABLE == null', when: 'always' }]], + [[{ if: '$VARIABLE != "the wrong value"', when: 'never' }, { if: '$VARIABLE == null', when: 'always' }]] + ] + end + + with_them do + it { is_expected.not_to be_included } + + it 'correctly populates when:' do + expect(seed_build.attributes).to include(when: 'never') + end + end + end + + context 'with an explicit `when: always`' do + where(:rule_set) do + [ + [[{ if: '$VARIABLE == null', when: 'always' }]], + [[{ if: '$VARIABLE == null', when: 'always' }, { if: '$VARIABLE == null', when: 'never' }]], + [[{ if: '$VARIABLE != "the wrong value"', when: 'always' }, { if: '$VARIABLE == null', when: 'never' }]] + ] + end + + with_them do + it { is_expected.to be_included } + + it 'correctly populates when:' do + expect(seed_build.attributes).to include(when: 'always') + end + end + end + + context 'with an explicit `when: on_failure`' do + where(:rule_set) do + [ + [[{ if: '$CI_JOB_NAME == "rspec" && $VAR == null', when: 'on_failure' }]], + [[{ if: '$VARIABLE != null', when: 'delayed', start_in: '1 day' }, { if: '$CI_JOB_NAME == "rspec"', when: 'on_failure' }]], + [[{ if: '$VARIABLE == "the wrong value"', when: 'delayed', start_in: '1 day' }, { if: '$CI_BUILD_NAME == "rspec"', when: 'on_failure' }]] + ] + end + + with_them do + it { is_expected.to be_included } + + it 'correctly populates when:' do + expect(seed_build.attributes).to include(when: 'on_failure') + end + end + end + + context 'with an explicit `when: delayed`' do + where(:rule_set) do + [ + [[{ if: '$VARIABLE == null', when: 'delayed', start_in: '1 day' }]], + [[{ if: '$VARIABLE == null', when: 'delayed', start_in: '1 day' }, { if: '$VARIABLE == null', when: 'never' }]], + [[{ if: '$VARIABLE != "the wrong value"', when: 'delayed', start_in: '1 day' }, { if: '$VARIABLE == null', when: 'never' }]] + ] + end + + with_them do + it { is_expected.to be_included } + + it 'correctly populates when:' do + expect(seed_build.attributes).to include(when: 'delayed', start_in: '1 day') + end + end + end + + context 'without an explicit when: value' do + where(:rule_set) do + [ + [[{ if: '$VARIABLE == null' }]], + [[{ if: '$VARIABLE == null' }, { if: '$VARIABLE == null' }]], + [[{ if: '$VARIABLE != "the wrong value"' }, { if: '$VARIABLE == null' }]] + ] + end + + with_them do + it { is_expected.to be_included } + + it 'correctly populates when:' do + expect(seed_build.attributes).to include(when: 'on_success') + end + end + end + end + + context 'with a matching changes: rule' do + let(:pipeline) do + create(:ci_pipeline, project: project).tap do |pipeline| + stub_pipeline_modified_paths(pipeline, %w[app/models/ci/pipeline.rb spec/models/ci/pipeline_spec.rb .gitlab-ci.yml]) + end + end + + context 'with an explicit `when: never`' do + where(:rule_set) do + [ + [[{ changes: %w[*/**/*.rb], when: 'never' }, { changes: %w[*/**/*.rb], when: 'always' }]], + [[{ changes: %w[app/models/ci/pipeline.rb], when: 'never' }, { changes: %w[app/models/ci/pipeline.rb], when: 'always' }]], + [[{ changes: %w[spec/**/*.rb], when: 'never' }, { changes: %w[spec/**/*.rb], when: 'always' }]], + [[{ changes: %w[*.yml], when: 'never' }, { changes: %w[*.yml], when: 'always' }]], + [[{ changes: %w[.*.yml], when: 'never' }, { changes: %w[.*.yml], when: 'always' }]], + [[{ changes: %w[**/*], when: 'never' }, { changes: %w[**/*], when: 'always' }]], + [[{ changes: %w[*/**/*.rb *.yml], when: 'never' }, { changes: %w[*/**/*.rb *.yml], when: 'always' }]], + [[{ changes: %w[.*.yml **/*], when: 'never' }, { changes: %w[.*.yml **/*], when: 'always' }]] + ] + end + + with_them do + it { is_expected.not_to be_included } + + it 'correctly populates when:' do + expect(seed_build.attributes).to include(when: 'never') + end + end + end + + context 'with an explicit `when: always`' do + where(:rule_set) do + [ + [[{ changes: %w[*/**/*.rb], when: 'always' }, { changes: %w[*/**/*.rb], when: 'never' }]], + [[{ changes: %w[app/models/ci/pipeline.rb], when: 'always' }, { changes: %w[app/models/ci/pipeline.rb], when: 'never' }]], + [[{ changes: %w[spec/**/*.rb], when: 'always' }, { changes: %w[spec/**/*.rb], when: 'never' }]], + [[{ changes: %w[*.yml], when: 'always' }, { changes: %w[*.yml], when: 'never' }]], + [[{ changes: %w[.*.yml], when: 'always' }, { changes: %w[.*.yml], when: 'never' }]], + [[{ changes: %w[**/*], when: 'always' }, { changes: %w[**/*], when: 'never' }]], + [[{ changes: %w[*/**/*.rb *.yml], when: 'always' }, { changes: %w[*/**/*.rb *.yml], when: 'never' }]], + [[{ changes: %w[.*.yml **/*], when: 'always' }, { changes: %w[.*.yml **/*], when: 'never' }]] + ] + end + + with_them do + it { is_expected.to be_included } + + it 'correctly populates when:' do + expect(seed_build.attributes).to include(when: 'always') + end + end + end + + context 'without an explicit when: value' do + where(:rule_set) do + [ + [[{ changes: %w[*/**/*.rb] }]], + [[{ changes: %w[app/models/ci/pipeline.rb] }]], + [[{ changes: %w[spec/**/*.rb] }]], + [[{ changes: %w[*.yml] }]], + [[{ changes: %w[.*.yml] }]], + [[{ changes: %w[**/*] }]], + [[{ changes: %w[*/**/*.rb *.yml] }]], + [[{ changes: %w[.*.yml **/*] }]] + ] + end + + with_them do + it { is_expected.to be_included } + + it 'correctly populates when:' do + expect(seed_build.attributes).to include(when: 'on_success') + end + end + end + end + + context 'with no matching rule' do + where(:rule_set) do + [ + [[{ if: '$VARIABLE != null', when: 'never' }]], + [[{ if: '$VARIABLE != null', when: 'never' }, { if: '$VARIABLE != null', when: 'always' }]], + [[{ if: '$VARIABLE == "the wrong value"', when: 'never' }, { if: '$VARIABLE != null', when: 'always' }]], + [[{ if: '$VARIABLE != null', when: 'always' }]], + [[{ if: '$VARIABLE != null', when: 'always' }, { if: '$VARIABLE != null', when: 'never' }]], + [[{ if: '$VARIABLE == "the wrong value"', when: 'always' }, { if: '$VARIABLE != null', when: 'never' }]], + [[{ if: '$VARIABLE != null' }]], + [[{ if: '$VARIABLE != null' }, { if: '$VARIABLE != null' }]], + [[{ if: '$VARIABLE == "the wrong value"' }, { if: '$VARIABLE != null' }]] + ] + end + + with_them do + it { is_expected.not_to be_included } + + it 'correctly populates when:' do + expect(seed_build.attributes).to include(when: 'never') + end + end + end + + context 'with no rules' do + let(:rule_set) { [] } + + it { is_expected.not_to be_included } + + it 'correctly populates when:' do + expect(seed_build.attributes).to include(when: 'never') + end + end + end end describe 'applying needs: dependency' do @@ -476,4 +755,10 @@ describe Gitlab::Ci::Pipeline::Seed::Build do end end end + + describe '#scoped_variables_hash' do + subject { seed_build.scoped_variables_hash } + + it { is_expected.to eq(seed_build.to_resource.scoped_variables_hash) } + end end diff --git a/spec/lib/gitlab/ci/yaml_processor_spec.rb b/spec/lib/gitlab/ci/yaml_processor_spec.rb index d5567b4f166..91c559dcd9b 100644 --- a/spec/lib/gitlab/ci/yaml_processor_spec.rb +++ b/spec/lib/gitlab/ci/yaml_processor_spec.rb @@ -125,9 +125,11 @@ module Gitlab describe 'delayed job entry' do context 'when delayed is defined' do let(:config) do - YAML.dump(rspec: { script: 'rollout 10%', - when: 'delayed', - start_in: '1 day' }) + YAML.dump(rspec: { + script: 'rollout 10%', + when: 'delayed', + start_in: '1 day' + }) end it 'has the attributes' do @@ -726,12 +728,12 @@ module Gitlab end end - describe "When" do - %w(on_success on_failure always).each do |when_state| - it "returns #{when_state} when defined" do + describe 'when:' do + (Gitlab::Ci::Config::Entry::Job::ALLOWED_WHEN - %w[delayed]).each do |when_state| + it "#{when_state} creates one build and sets when:" do config = YAML.dump({ - rspec: { script: "rspec", when: when_state } - }) + rspec: { script: 'rspec', when: when_state } + }) config_processor = Gitlab::Ci::YamlProcessor.new(config) builds = config_processor.stage_builds_attributes("test") @@ -740,6 +742,35 @@ module Gitlab expect(builds.first[:when]).to eq(when_state) end end + + context 'delayed' do + context 'with start_in' do + it 'creates one build and sets when:' do + config = YAML.dump({ + rspec: { script: 'rspec', when: 'delayed', start_in: '1 hour' } + }) + + config_processor = Gitlab::Ci::YamlProcessor.new(config) + builds = config_processor.stage_builds_attributes("test") + + expect(builds.size).to eq(1) + expect(builds.first[:when]).to eq('delayed') + expect(builds.first[:options][:start_in]).to eq('1 hour') + end + end + + context 'without start_in' do + it 'raises an error' do + config = YAML.dump({ + rspec: { script: 'rspec', when: 'delayed' } + }) + + expect do + Gitlab::Ci::YamlProcessor.new(config) + end.to raise_error(YamlProcessor::ValidationError, /start in should be a duration/) + end + end + end end describe 'Parallel' do @@ -1132,7 +1163,7 @@ module Gitlab it { expect { subject }.not_to raise_error } end - context 'needs to builds' do + context 'needs two builds' do let(:needs) { %w(build1 build2) } it "does create jobs with valid specification" do @@ -1169,7 +1200,7 @@ module Gitlab end end - context 'needs to builds defined as symbols' do + context 'needs two builds defined as symbols' do let(:needs) { [:build1, :build2] } it { expect { subject }.not_to raise_error } @@ -1195,6 +1226,67 @@ module Gitlab end end + describe 'rules' do + subject { Gitlab::Ci::YamlProcessor.new(YAML.dump(config)) } + + let(:config) do + { + var_default: { stage: 'build', script: 'test', rules: [{ if: '$VAR == null' }] }, + var_when: { stage: 'build', script: 'test', rules: [{ if: '$VAR == null', when: 'always' }] }, + var_and_changes: { stage: 'build', script: 'test', rules: [{ if: '$VAR == null', changes: %w[README], when: 'always' }] }, + changes_not_var: { stage: 'test', script: 'test', rules: [{ if: '$VAR != null', changes: %w[README] }] }, + var_not_changes: { stage: 'test', script: 'test', rules: [{ if: '$VAR == null', changes: %w[other/file.rb], when: 'always' }] }, + nothing: { stage: 'test', script: 'test', rules: [{ when: 'manual' }] }, + var_never: { stage: 'deploy', script: 'test', rules: [{ if: '$VAR == null', when: 'never' }] }, + var_delayed: { stage: 'deploy', script: 'test', rules: [{ if: '$VAR == null', when: 'delayed', start_in: '3 hours' }] }, + two_rules: { stage: 'deploy', script: 'test', rules: [{ if: '$VAR == null', when: 'on_success' }, { changes: %w[README], when: 'manual' }] } + } + end + + it 'raises no exceptions' do + expect { subject }.not_to raise_error + end + + it 'returns all jobs regardless of their inclusion' do + expect(subject.builds.count).to eq(config.keys.count) + end + + context 'used with job-level when' do + let(:config) do + { + var_default: { + stage: 'build', + script: 'test', + when: 'always', + rules: [{ if: '$VAR == null' }] + } + } + end + + it 'raises a ValidationError' do + expect { subject }.to raise_error(YamlProcessor::ValidationError, /may not be used with `rules`: when/) + end + end + + context 'used with job-level when:delayed' do + let(:config) do + { + var_default: { + stage: 'build', + script: 'test', + when: 'delayed', + start_in: '10 minutes', + rules: [{ if: '$VAR == null' }] + } + } + end + + it 'raises a ValidationError' do + expect { subject }.to raise_error(YamlProcessor::ValidationError, /may not be used with `rules`: when, start_in/) + end + end + end + describe "Hidden jobs" do let(:config_processor) { Gitlab::Ci::YamlProcessor.new(config) } subject { config_processor.stage_builds_attributes("test") } @@ -1513,7 +1605,7 @@ module Gitlab config = YAML.dump({ rspec: { script: "test", when: 1 } }) expect do Gitlab::Ci::YamlProcessor.new(config) - end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:rspec when should be on_success, on_failure, always, manual or delayed") + end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:rspec when should be one of: #{Gitlab::Ci::Config::Entry::Job::ALLOWED_WHEN.join(', ')}") end it "returns errors if job artifacts:name is not an a string" do diff --git a/spec/lib/gitlab/repository_cache_adapter_spec.rb b/spec/lib/gitlab/repository_cache_adapter_spec.rb index 0295138fc3a..04fc24b6205 100644 --- a/spec/lib/gitlab/repository_cache_adapter_spec.rb +++ b/spec/lib/gitlab/repository_cache_adapter_spec.rb @@ -4,6 +4,7 @@ describe Gitlab::RepositoryCacheAdapter do let(:project) { create(:project, :repository) } let(:repository) { project.repository } let(:cache) { repository.send(:cache) } + let(:redis_set_cache) { repository.send(:redis_set_cache) } describe '#cache_method_output', :use_clean_rails_memory_store_caching do let(:fallback) { 10 } @@ -206,9 +207,11 @@ describe Gitlab::RepositoryCacheAdapter do describe '#expire_method_caches' do it 'expires the caches of the given methods' do expect(cache).to receive(:expire).with(:rendered_readme) - expect(cache).to receive(:expire).with(:gitignore) + expect(cache).to receive(:expire).with(:branch_names) + expect(redis_set_cache).to receive(:expire).with(:rendered_readme) + expect(redis_set_cache).to receive(:expire).with(:branch_names) - repository.expire_method_caches(%i(rendered_readme gitignore)) + repository.expire_method_caches(%i(rendered_readme branch_names)) end it 'does not expire caches for non-existent methods' do diff --git a/spec/lib/gitlab/repository_set_cache_spec.rb b/spec/lib/gitlab/repository_set_cache_spec.rb new file mode 100644 index 00000000000..9695e13d842 --- /dev/null +++ b/spec/lib/gitlab/repository_set_cache_spec.rb @@ -0,0 +1,73 @@ +require 'spec_helper' + +describe Gitlab::RepositorySetCache, :clean_gitlab_redis_cache do + let(:project) { create(:project) } + let(:repository) { project.repository } + let(:namespace) { "#{repository.full_path}:#{project.id}" } + let(:cache) { described_class.new(repository) } + + describe '#cache_key' do + subject { cache.cache_key(:foo) } + + it 'includes the namespace' do + is_expected.to eq("foo:#{namespace}:set") + end + + context 'with a given namespace' do + let(:extra_namespace) { 'my:data' } + let(:cache) { described_class.new(repository, extra_namespace: extra_namespace) } + + it 'includes the full namespace' do + is_expected.to eq("foo:#{namespace}:#{extra_namespace}:set") + end + end + end + + describe '#expire' do + it 'expires the given key from the cache' do + cache.write(:foo, ['value']) + + expect(cache.read(:foo)).to contain_exactly('value') + expect(cache.expire(:foo)).to eq(1) + expect(cache.read(:foo)).to be_empty + end + end + + describe '#exist?' do + it 'checks whether the key exists' do + expect(cache.exist?(:foo)).to be(false) + + cache.write(:foo, ['value']) + + expect(cache.exist?(:foo)).to be(true) + end + end + + describe '#fetch' do + let(:blk) { -> { ['block value'] } } + + subject { cache.fetch(:foo, &blk) } + + it 'fetches the key from the cache when filled' do + cache.write(:foo, ['value']) + + is_expected.to contain_exactly('value') + end + + it 'writes the value of the provided block when empty' do + cache.expire(:foo) + + is_expected.to contain_exactly('block value') + expect(cache.read(:foo)).to contain_exactly('block value') + end + end + + describe '#include?' do + it 'checks inclusion in the Redis set' do + cache.write(:foo, ['value']) + + expect(cache.include?(:foo, 'value')).to be(true) + expect(cache.include?(:foo, 'bar')).to be(false) + end + end +end diff --git a/spec/lib/gitlab/sentry_spec.rb b/spec/lib/gitlab/sentry_spec.rb index af8b059b984..a48cc0d128a 100644 --- a/spec/lib/gitlab/sentry_spec.rb +++ b/spec/lib/gitlab/sentry_spec.rb @@ -65,6 +65,7 @@ describe Gitlab::Sentry do context '.track_acceptable_exception' do let(:exception) { RuntimeError.new('boom') } + let(:issue_url) { 'http://gitlab.com/gitlab-org/gitlab-ce/issues/1' } before do allow(described_class).to receive(:enabled?).and_return(true) @@ -74,7 +75,7 @@ describe Gitlab::Sentry do it 'calls Raven.capture_exception' do expected_extras = { some_other_info: 'info', - issue_url: 'http://gitlab.com/gitlab-org/gitlab-ce/issues/1' + issue_url: issue_url } expected_tags = { @@ -88,9 +89,33 @@ describe Gitlab::Sentry do described_class.track_acceptable_exception( exception, - issue_url: 'http://gitlab.com/gitlab-org/gitlab-ce/issues/1', + issue_url: issue_url, extra: { some_other_info: 'info' } ) end + + context 'the exception implements :sentry_extra_data' do + let(:extra_info) { { event: 'explosion', size: :massive } } + let(:exception) { double(message: 'bang!', sentry_extra_data: extra_info) } + + it 'includes the extra data from the exception in the tracking information' do + expect(Raven).to receive(:capture_exception) + .with(exception, a_hash_including(extra: a_hash_including(extra_info))) + + described_class.track_acceptable_exception(exception) + end + end + + context 'the exception implements :sentry_extra_data, which returns nil' do + let(:exception) { double(message: 'bang!', sentry_extra_data: nil) } + + it 'just includes the other extra info' do + extra_info = { issue_url: issue_url } + expect(Raven).to receive(:capture_exception) + .with(exception, a_hash_including(extra: a_hash_including(extra_info))) + + described_class.track_acceptable_exception(exception, extra_info) + end + end end end diff --git a/spec/lib/gitlab/sidekiq_middleware/metrics_spec.rb b/spec/lib/gitlab/sidekiq_middleware/metrics_spec.rb index c6df1c6a0d8..e430599bd94 100644 --- a/spec/lib/gitlab/sidekiq_middleware/metrics_spec.rb +++ b/spec/lib/gitlab/sidekiq_middleware/metrics_spec.rb @@ -13,7 +13,7 @@ describe Gitlab::SidekiqMiddleware::Metrics do let(:running_jobs_metric) { double('running jobs metric') } before do - allow(Gitlab::Metrics).to receive(:histogram).with(:sidekiq_jobs_completion_seconds, anything).and_return(completion_seconds_metric) + allow(Gitlab::Metrics).to receive(:histogram).with(:sidekiq_jobs_completion_seconds, anything, anything).and_return(completion_seconds_metric) allow(Gitlab::Metrics).to receive(:counter).with(:sidekiq_jobs_failed_total, anything).and_return(failed_total_metric) allow(Gitlab::Metrics).to receive(:counter).with(:sidekiq_jobs_retried_total, anything).and_return(retried_total_metric) allow(Gitlab::Metrics).to receive(:gauge).with(:sidekiq_running_jobs, anything, {}, :livesum).and_return(running_jobs_metric) diff --git a/spec/lib/gitlab/usage_data_counters/note_counter_spec.rb b/spec/lib/gitlab/usage_data_counters/note_counter_spec.rb index 1669a22879f..b385d1b07c7 100644 --- a/spec/lib/gitlab/usage_data_counters/note_counter_spec.rb +++ b/spec/lib/gitlab/usage_data_counters/note_counter_spec.rb @@ -26,16 +26,22 @@ describe Gitlab::UsageDataCounters::NoteCounter, :clean_gitlab_redis_shared_stat end it_behaves_like 'a note usage counter', :create, 'Snippet' + it_behaves_like 'a note usage counter', :create, 'MergeRequest' + it_behaves_like 'a note usage counter', :create, 'Commit' describe '.totals' do let(:combinations) do [ - [:create, 'Snippet', 3] + [:create, 'Snippet', 3], + [:create, 'MergeRequest', 4], + [:create, 'Commit', 5] ] end let(:expected_totals) do - { snippet_comment: 3 } + { snippet_comment: 3, + merge_request_comment: 4, + commit_comment: 5 } end before do @@ -57,14 +63,18 @@ describe Gitlab::UsageDataCounters::NoteCounter, :clean_gitlab_redis_shared_stat let(:unknown_event_error) { Gitlab::UsageDataCounters::BaseCounter::UnknownEvent } where(:event, :noteable_type, :expected_count, :should_raise) do - :create | 'Snippet' | 1 | false - :wibble | 'Snippet' | 0 | true - :create | 'Issue' | 0 | false - :wibble | 'Issue' | 0 | false + :create | 'Snippet' | 1 | false + :wibble | 'Snippet' | 0 | true + :create | 'MergeRequest' | 1 | false + :wibble | 'MergeRequest' | 0 | true + :create | 'Commit' | 1 | false + :wibble | 'Commit' | 0 | true + :create | 'Issue' | 0 | false + :wibble | 'Issue' | 0 | false end with_them do - it "handles event" do + it 'handles event' do if should_raise expect { described_class.count(event, noteable_type) }.to raise_error(unknown_event_error) else diff --git a/spec/lib/gitlab/usage_data_spec.rb b/spec/lib/gitlab/usage_data_spec.rb index 64254674157..dda119e09b1 100644 --- a/spec/lib/gitlab/usage_data_spec.rb +++ b/spec/lib/gitlab/usage_data_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::UsageData do @@ -34,7 +36,7 @@ describe Gitlab::UsageData do subject { described_class.data } - it "gathers usage data" do + it 'gathers usage data' do expect(subject.keys).to include(*%i( active_user_count counts @@ -66,6 +68,8 @@ describe Gitlab::UsageData do snippet_create: a_kind_of(Integer), snippet_update: a_kind_of(Integer), snippet_comment: a_kind_of(Integer), + merge_request_comment: a_kind_of(Integer), + commit_comment: a_kind_of(Integer), wiki_pages_create: a_kind_of(Integer), wiki_pages_update: a_kind_of(Integer), wiki_pages_delete: a_kind_of(Integer), @@ -78,7 +82,7 @@ describe Gitlab::UsageData do ) end - it "gathers usage counts" do + it 'gathers usage counts' do expected_keys = %i( assignee_lists boards @@ -248,7 +252,7 @@ describe Gitlab::UsageData do describe '#license_usage_data' do subject { described_class.license_usage_data } - it "gathers license data" do + it 'gathers license data' do expect(subject[:uuid]).to eq(Gitlab::CurrentSettings.uuid) expect(subject[:version]).to eq(Gitlab::VERSION) expect(subject[:installation_type]).to eq('gitlab-development-kit') diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index 419e1dc2459..79395fcc994 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -1223,36 +1223,66 @@ describe Repository do end describe '#branch_exists?' do - it 'uses branch_names' do - allow(repository).to receive(:branch_names).and_return(['foobar']) + let(:branch) { repository.root_ref } - expect(repository.branch_exists?('foobar')).to eq(true) - expect(repository.branch_exists?('master')).to eq(false) + subject { repository.branch_exists?(branch) } + + it 'delegates to branch_names when the cache is empty' do + repository.expire_branches_cache + + expect(repository).to receive(:branch_names).and_call_original + is_expected.to eq(true) + end + + it 'uses redis set caching when the cache is filled' do + repository.branch_names # ensure the branch name cache is filled + + expect(repository) + .to receive(:branch_names_include?) + .with(branch) + .and_call_original + + is_expected.to eq(true) end end describe '#tag_exists?' do - it 'uses tag_names' do - allow(repository).to receive(:tag_names).and_return(['foobar']) + let(:tag) { repository.tags.first.name } + + subject { repository.tag_exists?(tag) } + + it 'delegates to tag_names when the cache is empty' do + repository.expire_tags_cache + + expect(repository).to receive(:tag_names).and_call_original + is_expected.to eq(true) + end + + it 'uses redis set caching when the cache is filled' do + repository.tag_names # ensure the tag name cache is filled + + expect(repository) + .to receive(:tag_names_include?) + .with(tag) + .and_call_original - expect(repository.tag_exists?('foobar')).to eq(true) - expect(repository.tag_exists?('master')).to eq(false) + is_expected.to eq(true) end end - describe '#branch_names', :use_clean_rails_memory_store_caching do + describe '#branch_names', :clean_gitlab_redis_cache do let(:fake_branch_names) { ['foobar'] } it 'gets cached across Repository instances' do allow(repository.raw_repository).to receive(:branch_names).once.and_return(fake_branch_names) - expect(repository.branch_names).to eq(fake_branch_names) + expect(repository.branch_names).to match_array(fake_branch_names) fresh_repository = Project.find(project.id).repository expect(fresh_repository.object_id).not_to eq(repository.object_id) expect(fresh_repository.raw_repository).not_to receive(:branch_names) - expect(fresh_repository.branch_names).to eq(fake_branch_names) + expect(fresh_repository.branch_names).to match_array(fake_branch_names) end end diff --git a/spec/presenters/blobs/unfold_presenter_spec.rb b/spec/presenters/blobs/unfold_presenter_spec.rb index ab3f8080257..83004809536 100644 --- a/spec/presenters/blobs/unfold_presenter_spec.rb +++ b/spec/presenters/blobs/unfold_presenter_spec.rb @@ -10,16 +10,31 @@ describe Blobs::UnfoldPresenter do let(:subject) { described_class.new(blob, params) } describe '#initialize' do + let(:result) { subject } + + context 'with empty params' do + let(:params) { {} } + + it 'sets default attributes' do + expect(result.full?).to eq(false) + expect(result.since).to eq(1) + expect(result.to).to eq(1) + expect(result.bottom).to eq(false) + expect(result.unfold).to eq(true) + expect(result.offset).to eq(0) + expect(result.indent).to eq(0) + end + end + context 'when full is false' do let(:params) { { full: false, since: 2, to: 3, bottom: false, offset: 1, indent: 1 } } it 'sets attributes' do - result = subject - expect(result.full?).to eq(false) expect(result.since).to eq(2) expect(result.to).to eq(3) expect(result.bottom).to eq(false) + expect(result.unfold).to eq(true) expect(result.offset).to eq(1) expect(result.indent).to eq(1) end @@ -29,12 +44,11 @@ describe Blobs::UnfoldPresenter do let(:params) { { full: true, since: 2, to: 3, bottom: false, offset: 1, indent: 1 } } it 'sets other attributes' do - result = subject - expect(result.full?).to eq(true) expect(result.since).to eq(1) expect(result.to).to eq(blob.lines.size) expect(result.bottom).to eq(false) + expect(result.unfold).to eq(false) expect(result.offset).to eq(0) expect(result.indent).to eq(0) end @@ -44,12 +58,11 @@ describe Blobs::UnfoldPresenter do let(:params) { { full: false, since: 2, to: -1, bottom: true, offset: 1, indent: 1 } } it 'sets other attributes' do - result = subject - expect(result.full?).to eq(false) expect(result.since).to eq(2) expect(result.to).to eq(blob.lines.size) expect(result.bottom).to eq(false) + expect(result.unfold).to eq(false) expect(result.offset).to eq(0) expect(result.indent).to eq(0) end diff --git a/spec/requests/api/issues/get_group_issues_spec.rb b/spec/requests/api/issues/get_group_issues_spec.rb index 5916bb11516..c487471e4a1 100644 --- a/spec/requests/api/issues/get_group_issues_spec.rb +++ b/spec/requests/api/issues/get_group_issues_spec.rb @@ -342,6 +342,14 @@ describe API::Issues do group_project.add_reporter(user) end + it 'exposes known attributes' do + get api(base_url, admin) + + expect(response).to have_gitlab_http_status(200) + expect(json_response.last.keys).to include(*%w(id iid project_id title description)) + expect(json_response.last).not_to have_key('subscribed') + end + it 'returns all group issues (including opened and closed)' do get api(base_url, admin) diff --git a/spec/requests/api/issues/get_project_issues_spec.rb b/spec/requests/api/issues/get_project_issues_spec.rb index f7ca6fd1e0a..521d6b88734 100644 --- a/spec/requests/api/issues/get_project_issues_spec.rb +++ b/spec/requests/api/issues/get_project_issues_spec.rb @@ -575,6 +575,7 @@ describe API::Issues do expect(json_response['assignee']).to be_a Hash expect(json_response['author']).to be_a Hash expect(json_response['confidential']).to be_falsy + expect(json_response['subscribed']).to be_truthy end it 'exposes the closed_at attribute' do diff --git a/spec/requests/api/issues/issues_spec.rb b/spec/requests/api/issues/issues_spec.rb index d195f54be11..27cf66629fe 100644 --- a/spec/requests/api/issues/issues_spec.rb +++ b/spec/requests/api/issues/issues_spec.rb @@ -216,6 +216,10 @@ describe API::Issues do expect_paginated_array_response([issue.id, closed_issue.id]) expect(json_response.first['title']).to eq(issue.title) expect(json_response.last).to have_key('web_url') + # Calculating the value of subscribed field triggers Markdown + # processing. We can't do that for multiple issues / merge + # requests in a single API request. + expect(json_response.last).not_to have_key('subscribed') end it 'returns an array of closed issues' do diff --git a/spec/requests/rack_attack_global_spec.rb b/spec/requests/rack_attack_global_spec.rb index d832963292c..478f09a7881 100644 --- a/spec/requests/rack_attack_global_spec.rb +++ b/spec/requests/rack_attack_global_spec.rb @@ -112,9 +112,9 @@ describe 'Rack Attack global throttles' do arguments = { message: 'Rack_Attack', env: :throttle, - ip: '127.0.0.1', + remote_ip: '127.0.0.1', request_method: 'GET', - fullpath: get_args.first, + path: get_args.first, user_id: user.id, username: user.username } @@ -213,9 +213,9 @@ describe 'Rack Attack global throttles' do arguments = { message: 'Rack_Attack', env: :throttle, - ip: '127.0.0.1', + remote_ip: '127.0.0.1', request_method: 'GET', - fullpath: '/users/sign_in' + path: '/users/sign_in' } expect(Gitlab::AuthLogger).to receive(:error).with(arguments) @@ -377,9 +377,9 @@ describe 'Rack Attack global throttles' do arguments = { message: 'Rack_Attack', env: :throttle, - ip: '127.0.0.1', + remote_ip: '127.0.0.1', request_method: 'GET', - fullpath: '/dashboard/snippets', + path: '/dashboard/snippets', user_id: user.id, username: user.username } diff --git a/spec/support/helpers/stub_gitlab_calls.rb b/spec/support/helpers/stub_gitlab_calls.rb index badea94352a..7d10cffe920 100644 --- a/spec/support/helpers/stub_gitlab_calls.rb +++ b/spec/support/helpers/stub_gitlab_calls.rb @@ -22,6 +22,10 @@ module StubGitlabCalls allow_any_instance_of(Ci::Pipeline).to receive(:ci_yaml_file) { ci_yaml } end + def stub_pipeline_modified_paths(pipeline, modified_paths) + allow(pipeline).to receive(:modified_paths).and_return(modified_paths) + end + def stub_repository_ci_yaml_file(sha:, path: '.gitlab-ci.yml') allow_any_instance_of(Repository) .to receive(:gitlab_ci_yml_for).with(sha, path) diff --git a/spec/support/shared_examples/controllers/external_authorization_service_shared_examples.rb b/spec/support/shared_examples/controllers/external_authorization_service_shared_examples.rb index 2faa0cf8c1c..d8a1ae83f61 100644 --- a/spec/support/shared_examples/controllers/external_authorization_service_shared_examples.rb +++ b/spec/support/shared_examples/controllers/external_authorization_service_shared_examples.rb @@ -8,7 +8,7 @@ shared_examples 'disabled when using an external authorization service' do it 'works when the feature is not enabled' do subject - expect(response).to be_success + expect(response).to be_successful end it 'renders a 404 with a message when the feature is enabled' do diff --git a/yarn.lock b/yarn.lock index a295039ec54..525c77e41d2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9,7 +9,7 @@ dependencies: "@babel/highlight" "^7.0.0" -"@babel/core@>=7.2.2", "@babel/core@^7.1.0", "@babel/core@^7.1.2", "@babel/core@^7.4.4": +"@babel/core@>=7.2.2", "@babel/core@^7.1.0", "@babel/core@^7.1.2", "@babel/core@^7.5.5": version "7.5.5" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.5.5.tgz#17b2686ef0d6bc58f963dddd68ab669755582c30" integrity sha512-i4qoSr2KTtce0DmkuuQBV4AuQgGPUcPXMr9L5MyYAtk06z068lQ10a4O009fe5OB/DfNV+h+qqT7ddNV8UnRjg== @@ -139,16 +139,16 @@ "@babel/types" "^7.0.0" "@babel/helper-module-transforms@^7.1.0", "@babel/helper-module-transforms@^7.4.4": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.4.4.tgz#96115ea42a2f139e619e98ed46df6019b94414b8" - integrity sha512-3Z1yp8TVQf+B4ynN7WoHPKS8EkdTbgAEy0nU0rs/1Kw4pDgmvYH3rz3aI11KgxKCba2cn7N+tqzV1mY2HMN96w== + version "7.5.5" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.5.5.tgz#f84ff8a09038dcbca1fd4355661a500937165b4a" + integrity sha512-jBeCvETKuJqeiaCdyaheF40aXnnU1+wkSiUs/IQg3tB85up1LyL8x77ClY8qJpuRJUcXQo+ZtdNESmZl4j56Pw== dependencies: "@babel/helper-module-imports" "^7.0.0" "@babel/helper-simple-access" "^7.1.0" "@babel/helper-split-export-declaration" "^7.4.4" "@babel/template" "^7.4.4" - "@babel/types" "^7.4.4" - lodash "^4.17.11" + "@babel/types" "^7.5.5" + lodash "^4.17.13" "@babel/helper-optimise-call-expression@^7.0.0": version "7.0.0" @@ -163,11 +163,11 @@ integrity sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA== "@babel/helper-regex@^7.0.0", "@babel/helper-regex@^7.4.4": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.4.4.tgz#a47e02bc91fb259d2e6727c2a30013e3ac13c4a2" - integrity sha512-Y5nuB/kESmR3tKjU8Nkn1wMGEx1tjJX076HBMeL3XLQCu6vA/YRzuTW0bbb+qRnXvQGn+d6Rx953yffl8vEy7Q== + version "7.5.5" + resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.5.5.tgz#0aa6824f7100a2e0e89c1527c23936c152cab351" + integrity sha512-CkCYQLkfkiugbRDO8eZn6lRuR8kzZoGXCg3149iTk5se7g6qykSpy3+hELSwquhu+TgHn8nkLiBwHvNX8Hofcw== dependencies: - lodash "^4.17.11" + lodash "^4.17.13" "@babel/helper-remap-async-to-generator@^7.1.0": version "7.1.0" @@ -225,9 +225,9 @@ "@babel/types" "^7.5.5" "@babel/highlight@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.0.0.tgz#f710c38c8d458e6dd9a201afb637fcb781ce99e4" - integrity sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw== + version "7.5.0" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.5.0.tgz#56d11312bd9248fa619591d02472be6e8cb32540" + integrity sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ== dependencies: chalk "^2.0.0" esutils "^2.0.2" @@ -252,7 +252,7 @@ "@babel/helper-remap-async-to-generator" "^7.1.0" "@babel/plugin-syntax-async-generators" "^7.2.0" -"@babel/plugin-proposal-class-properties@^7.1.0", "@babel/plugin-proposal-class-properties@^7.4.4": +"@babel/plugin-proposal-class-properties@^7.1.0", "@babel/plugin-proposal-class-properties@^7.5.5": version "7.5.5" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.5.5.tgz#a974cfae1e37c3110e71f3c6a2e48b8e71958cd4" integrity sha512-AF79FsnWFxjlaosgdi421vmYG6/jg79bVD0dpD44QdgobzHKuLZ6S3vl8la9qIeSwGi8i1fS0O1mfuDAAdo1/A== @@ -833,7 +833,7 @@ "@babel/helper-regex" "^7.4.4" regexpu-core "^4.5.4" -"@babel/preset-env@^7.1.0", "@babel/preset-env@^7.4.4": +"@babel/preset-env@^7.1.0", "@babel/preset-env@^7.5.5": version "7.5.5" resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.5.5.tgz#bc470b53acaa48df4b8db24a570d6da1fef53c9a" integrity sha512-GMZQka/+INwsMz1A5UEql8tG015h5j/qjptpKY2gJ7giy8ohzU710YciJB5rcKsWGWHiW3RUnHib0E5/m3Tp3A== @@ -914,9 +914,9 @@ integrity sha512-FBMd0IiARPtH5aaOFUVki6evHiJQiY0pFy7fizyRF7dtwc+el3nwpzvhb9qBNzceG1OIJModG1xpE0DDFjPXwA== "@babel/standalone@^7.0.0": - version "7.3.4" - resolved "https://registry.yarnpkg.com/@babel/standalone/-/standalone-7.3.4.tgz#b622c1e522acef91b2a14f22bdcdd4f935a1a474" - integrity sha512-4L9c5i4WlGqbrjOVX0Yp8TIR5cEiw1/tPYYZENW/iuO2uI6viY38U7zALidzNfGdZIwNc+A/AWqMEWKeScWkBg== + version "7.5.5" + resolved "https://registry.yarnpkg.com/@babel/standalone/-/standalone-7.5.5.tgz#9d3143f6078ff408db694a4254bd6f03c5c33962" + integrity sha512-YIp5taErC4uvp4d5urJtWMui3cpvZt83x57l4oVJNvFtDzumf3pMgRmoTSpGuEzh1yzo7jHhg3mbQmMhmKPbjA== "@babel/template@^7.1.0", "@babel/template@^7.4.0", "@babel/template@^7.4.4": version "7.4.4" |