diff options
47 files changed, 330 insertions, 145 deletions
@@ -26,7 +26,7 @@ gem 'marginalia', '~> 1.8.0' # Authentication libraries gem 'devise', '~> 4.6' -gem 'doorkeeper', '~> 4.3' +gem 'doorkeeper', '~> 4.4.3' gem 'doorkeeper-openid_connect', '~> 1.5' gem 'omniauth', '~> 1.8' gem 'omniauth-auth0', '~> 2.0.0' diff --git a/Gemfile.lock b/Gemfile.lock index 500f1729d08..af8941611e4 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -231,7 +231,7 @@ GEM docile (1.3.1) domain_name (0.5.20180417) unf (>= 0.0.5, < 1.0.0) - doorkeeper (4.3.2) + doorkeeper (4.4.3) railties (>= 4.2) doorkeeper-openid_connect (1.5.0) doorkeeper (~> 4.3) @@ -1180,7 +1180,7 @@ DEPENDENCIES diff_match_patch (~> 0.1.0) diffy (~> 3.1.0) discordrb-webhooks-blackst0ne (~> 3.3) - doorkeeper (~> 4.3) + doorkeeper (~> 4.4.3) doorkeeper-openid_connect (~> 1.5) ed25519 (~> 1.2) elasticsearch-api (~> 6.8) diff --git a/app/assets/javascripts/self_monitor/index.js b/app/assets/javascripts/self_monitor/index.js index 42c94e11989..7db87b4c627 100644 --- a/app/assets/javascripts/self_monitor/index.js +++ b/app/assets/javascripts/self_monitor/index.js @@ -4,15 +4,12 @@ import SelfMonitorForm from './components/self_monitor_form.vue'; export default () => { const el = document.querySelector('.js-self-monitoring-settings'); - let selfMonitorProjectCreated; if (el) { - selfMonitorProjectCreated = el.dataset.selfMonitoringProjectExists; // eslint-disable-next-line no-new new Vue({ el, store: store({ - projectEnabled: selfMonitorProjectCreated, ...el.dataset, }), render(createElement) { diff --git a/app/assets/javascripts/self_monitor/store/actions.js b/app/assets/javascripts/self_monitor/store/actions.js index f8430a9b136..10deec6921c 100644 --- a/app/assets/javascripts/self_monitor/store/actions.js +++ b/app/assets/javascripts/self_monitor/store/actions.js @@ -52,7 +52,7 @@ export const requestCreateProjectStatus = ({ dispatch, state }, jobId) => { }); }; -export const requestCreateProjectSuccess = ({ commit }, selfMonitorData) => { +export const requestCreateProjectSuccess = ({ commit, dispatch }, selfMonitorData) => { commit(types.SET_LOADING, false); commit(types.SET_PROJECT_URL, selfMonitorData.project_full_path); commit(types.SET_ALERT_CONTENT, { @@ -62,6 +62,7 @@ export const requestCreateProjectSuccess = ({ commit }, selfMonitorData) => { }); commit(types.SET_SHOW_ALERT, true); commit(types.SET_PROJECT_CREATED, true); + dispatch('setSelfMonitor', true); }; export const requestCreateProjectError = ({ commit }, error) => { diff --git a/app/assets/javascripts/self_monitor/store/state.js b/app/assets/javascripts/self_monitor/store/state.js index b8b4a4af614..a0ce88ff58c 100644 --- a/app/assets/javascripts/self_monitor/store/state.js +++ b/app/assets/javascripts/self_monitor/store/state.js @@ -1,8 +1,8 @@ import { parseBoolean } from '~/lib/utils/common_utils'; export default (initialState = {}) => ({ - projectEnabled: parseBoolean(initialState.projectEnabled) || false, - projectCreated: parseBoolean(initialState.selfMonitorProjectCreated) || false, + projectEnabled: parseBoolean(initialState.selfMonitoringProjectExists) || false, + projectCreated: parseBoolean(initialState.selfMonitoringProjectExists) || false, createProjectEndpoint: initialState.createSelfMonitoringProjectPath || '', deleteProjectEndpoint: initialState.deleteSelfMonitoringProjectPath || '', createProjectStatusEndpoint: initialState.statusCreateSelfMonitoringProjectPath || '', diff --git a/app/controllers/admin/applications_controller.rb b/app/controllers/admin/applications_controller.rb index 907b295870d..c017ecee054 100644 --- a/app/controllers/admin/applications_controller.rb +++ b/app/controllers/admin/applications_controller.rb @@ -55,6 +55,8 @@ class Admin::ApplicationsController < Admin::ApplicationController # Only allow a trusted parameter "white list" through. def application_params - params.require(:doorkeeper_application).permit(:name, :redirect_uri, :trusted, :scopes) + params + .require(:doorkeeper_application) + .permit(:name, :redirect_uri, :trusted, :scopes, :confidential) end end diff --git a/app/controllers/groups/registry/repositories_controller.rb b/app/controllers/groups/registry/repositories_controller.rb index cfddd8a3ba9..a4ef33ecc6a 100644 --- a/app/controllers/groups/registry/repositories_controller.rb +++ b/app/controllers/groups/registry/repositories_controller.rb @@ -7,13 +7,13 @@ module Groups before_action :feature_flag_group_container_registry_browser! def index - track_event(:list_repositories) - respond_to do |format| format.html format.json do @images = group.container_repositories.with_api_entity_associations + track_event(:list_repositories) + render json: ContainerRepositoriesSerializer .new(current_user: current_user) .represent_read_only(@images) diff --git a/app/controllers/projects/registry/repositories_controller.rb b/app/controllers/projects/registry/repositories_controller.rb index 9405fd526ae..5e933b3b51f 100644 --- a/app/controllers/projects/registry/repositories_controller.rb +++ b/app/controllers/projects/registry/repositories_controller.rb @@ -7,12 +7,13 @@ module Projects before_action :ensure_root_container_repository!, only: [:index] def index - @images = project.container_repositories - track_event(:list_repositories) - respond_to do |format| format.html format.json do + @images = project.container_repositories + + track_event(:list_repositories) + render json: ContainerRepositoriesSerializer .new(project: project, current_user: current_user) .represent(@images) diff --git a/app/models/user.rb b/app/models/user.rb index e86c0a1826d..bc113c72762 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -101,6 +101,7 @@ class User < ApplicationRecord # Groups has_many :members + has_one :max_access_level_membership, -> { select(:id, :user_id, :access_level).order(access_level: :desc).readonly }, class_name: 'Member' has_many :group_members, -> { where(requested_at: nil) }, source: 'GroupMember' has_many :groups, through: :group_members has_many :owned_groups, -> { where(members: { access_level: Gitlab::Access::OWNER }) }, through: :group_members, source: :group @@ -1027,7 +1028,7 @@ class User < ApplicationRecord end def highest_role - members.maximum(:access_level) || Gitlab::Access::NO_ACCESS + max_access_level_membership&.access_level || Gitlab::Access::NO_ACCESS end def accessible_deploy_keys diff --git a/app/views/admin/applications/_form.html.haml b/app/views/admin/applications/_form.html.haml index 21e84016c66..8338401bea5 100644 --- a/app/views/admin/applications/_form.html.haml +++ b/app/views/admin/applications/_form.html.haml @@ -30,6 +30,14 @@ %span.form-text.text-muted Trusted applications are automatically authorized on GitLab OAuth flow. + = content_tag :div, class: 'form-group row' do + .col-sm-2.col-form-label.pt-0 + = f.label :confidential + .col-sm-10 + = f.check_box :confidential + %span.form-text.text-muted + = _('The application will be used where the client secret can be kept confidential. Native mobile apps and Single Page Apps are considered non-confidential.') + .form-group.row .col-sm-2.col-form-label.pt-0 = f.label :scopes diff --git a/app/views/admin/applications/index.html.haml b/app/views/admin/applications/index.html.haml index 758d722cc63..c3861f335b8 100644 --- a/app/views/admin/applications/index.html.haml +++ b/app/views/admin/applications/index.html.haml @@ -12,6 +12,7 @@ %th Callback URL %th Clients %th Trusted + %th Confidential %th %th %tbody.oauth-applications @@ -21,6 +22,7 @@ %td= application.redirect_uri %td= @application_counts[application.id].to_i %td= application.trusted? ? 'Y': 'N' + %td= application.confidential? ? 'Y': 'N' %td= link_to 'Edit', edit_admin_application_path(application), class: 'btn btn-link' %td= render 'delete_form', application: application = paginate @applications, theme: 'gitlab' diff --git a/app/views/admin/applications/show.html.haml b/app/views/admin/applications/show.html.haml index aca9302aff7..146674a2fac 100644 --- a/app/views/admin/applications/show.html.haml +++ b/app/views/admin/applications/show.html.haml @@ -36,6 +36,12 @@ %td = @application.trusted? ? 'Y' : 'N' + %tr + %td + Confidential + %td + = @application.confidential? ? 'Y' : 'N' + = render "shared/tokens/scopes_list", token: @application .form-actions diff --git a/app/views/doorkeeper/applications/_form.html.haml b/app/views/doorkeeper/applications/_form.html.haml index 78904f550c7..79abe31a056 100644 --- a/app/views/doorkeeper/applications/_form.html.haml +++ b/app/views/doorkeeper/applications/_form.html.haml @@ -15,6 +15,12 @@ %span.form-text.text-muted = _('Use <code>%{native_redirect_uri}</code> for local tests').html_safe % { native_redirect_uri: Doorkeeper.configuration.native_redirect_uri } + .form-group.form-check + = f.check_box :confidential, class: 'form-check-input' + = f.label :confidential, class: 'label-bold form-check-label' + %span.form-text.text-muted + = _('The application will be used where the client secret can be kept confidential. Native mobile apps and Single Page Apps are considered non-confidential.') + .form-group = f.label :scopes, class: 'label-bold' = render 'shared/tokens/scopes_form', prefix: 'doorkeeper_application', token: application, scopes: @scopes diff --git a/app/views/doorkeeper/applications/show.html.haml b/app/views/doorkeeper/applications/show.html.haml index 8a1b7500abf..7b29269dbb1 100644 --- a/app/views/doorkeeper/applications/show.html.haml +++ b/app/views/doorkeeper/applications/show.html.haml @@ -34,6 +34,12 @@ %div %span.monospace= uri + %tr + %td + = _('Confidential') + %td + = @application.confidential? ? _('Yes') : _('No') + = render "shared/tokens/scopes_list", token: @application .form-actions diff --git a/changelogs/unreleased/118487-no-limits-on-size-of-diffs-returned-by-the-projects-id-repository-.yml b/changelogs/unreleased/118487-no-limits-on-size-of-diffs-returned-by-the-projects-id-repository-.yml new file mode 100644 index 00000000000..4abbb275c28 --- /dev/null +++ b/changelogs/unreleased/118487-no-limits-on-size-of-diffs-returned-by-the-projects-id-repository-.yml @@ -0,0 +1,5 @@ +--- +title: Limit size of diffs returned by /projects/:id/repository/compare API endpoint +merge_request: 22658 +author: +type: fixed diff --git a/changelogs/unreleased/198042-argumenterror-wrong-number-of-arguments-given-1-expected-2.yml b/changelogs/unreleased/198042-argumenterror-wrong-number-of-arguments-given-1-expected-2.yml new file mode 100644 index 00000000000..2757205c14e --- /dev/null +++ b/changelogs/unreleased/198042-argumenterror-wrong-number-of-arguments-given-1-expected-2.yml @@ -0,0 +1,6 @@ +--- +title: Fixes AutoMergeProcessWorker failing when merge train service is not available + for a merge request +merge_request: 23407 +author: +type: fixed diff --git a/changelogs/unreleased/ab-tie-breaker-order.yml b/changelogs/unreleased/ab-tie-breaker-order.yml new file mode 100644 index 00000000000..fb4a0b1b8bd --- /dev/null +++ b/changelogs/unreleased/ab-tie-breaker-order.yml @@ -0,0 +1,5 @@ +--- +title: Let tie breaker order follow primary sort direction (API) +merge_request: 22795 +author: +type: changed diff --git a/changelogs/unreleased/expose_is_using_seat_for_group_members.yml b/changelogs/unreleased/expose_is_using_seat_for_group_members.yml new file mode 100644 index 00000000000..1ed0a4e7c41 --- /dev/null +++ b/changelogs/unreleased/expose_is_using_seat_for_group_members.yml @@ -0,0 +1,5 @@ +--- +title: Expose is_using_seat attribute for Member in API +merge_request: 21496 +author: +type: added diff --git a/changelogs/unreleased/jhyson-doorkeeper_upgrade.yml b/changelogs/unreleased/jhyson-doorkeeper_upgrade.yml new file mode 100644 index 00000000000..8716b84bdfe --- /dev/null +++ b/changelogs/unreleased/jhyson-doorkeeper_upgrade.yml @@ -0,0 +1,5 @@ +--- +title: Upgrade Doorkeeper to 4.4.3 to address CVE-2018-1000211 +merge_request: 20953 +author: +type: security diff --git a/config/initializers/doorkeeper.rb b/config/initializers/doorkeeper.rb index 6be5c00daaa..7e787c35982 100644 --- a/config/initializers/doorkeeper.rb +++ b/config/initializers/doorkeeper.rb @@ -118,8 +118,8 @@ end # app created does not match the complete list of scopes of the configured app. # It also prevents the OAuth authorize application window to appear every time. -# Remove after we upgrade the doorkeeper gem from version 4.3.2 -if Doorkeeper.gem_version > Gem::Version.new('4.3.2') +# Remove after we upgrade the doorkeeper gem from version 4.x +if Doorkeeper.gem_version > Gem::Version.new('5.0.0') raise "Doorkeeper was upgraded, please remove the monkey patch in #{__FILE__}" end diff --git a/db/migrate/20191127163053_add_confidential_to_doorkeeper_application.rb b/db/migrate/20191127163053_add_confidential_to_doorkeeper_application.rb new file mode 100644 index 00000000000..12e22b4744c --- /dev/null +++ b/db/migrate/20191127163053_add_confidential_to_doorkeeper_application.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +class AddConfidentialToDoorkeeperApplication < ActiveRecord::Migration[5.2] + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + disable_ddl_transaction! + + def up + add_column_with_default( # rubocop:disable Migration/AddColumnWithDefault + :oauth_applications, + :confidential, + :boolean, + default: false, # assume all existing applications are non-confidential + allow_null: false + ) + + # set the default to true so that all future applications are confidential by default + change_column_default(:oauth_applications, :confidential, true) + end + + def down + remove_column :oauth_applications, :confidential + end +end diff --git a/db/schema.rb b/db/schema.rb index c6c51481d1b..f6b44f9de00 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -2853,6 +2853,7 @@ ActiveRecord::Schema.define(version: 2020_01_21_132641) do t.integer "owner_id" t.string "owner_type" t.boolean "trusted", default: false, null: false + t.boolean "confidential", default: true, null: false t.index ["owner_id", "owner_type"], name: "index_oauth_applications_on_owner_id_and_owner_type" t.index ["uid"], name: "index_oauth_applications_on_uid", unique: true end diff --git a/doc/administration/operations/extra_sidekiq_processes.md b/doc/administration/operations/extra_sidekiq_processes.md index 8ab75da3501..fd5f9fe6c26 100644 --- a/doc/administration/operations/extra_sidekiq_processes.md +++ b/doc/administration/operations/extra_sidekiq_processes.md @@ -284,32 +284,3 @@ command and not the PID(s) of the started Sidekiq processes. The Rails environment can be set by passing the `--environment` flag to the `sidekiq-cluster` command, or by setting `RAILS_ENV` to a non-empty value. The default value can be found in `/opt/gitlab/etc/gitlab-rails/env/RAILS_ENV`. - -### Using negation - -You're able to run all queues in the `all_queues.yml` file (or the equivalent EE -file) on a single or multiple processes with exceptions using the `--negate` -flag. - -For example, say you want to run a single process for all queues, -except `process_commit` and `post_receive`: - -```bash -/opt/gitlab/embedded/service/gitlab-rails/ee/bin/sidekiq-cluster process_commit,post_receive --negate -``` - -For multiple processes of all queues (except `process_commit` and `post_receive`): - -```bash -/opt/gitlab/embedded/service/gitlab-rails/ee/bin/sidekiq-cluster process_commit,post_receive process_commit,post_receive --negate -``` - -### Limiting concurrency - -By default, `sidekiq-cluster` will spin up extra Sidekiq processes that use -one thread per queue up to a maximum of 50. If you wish to change the cap, use -the `-m N` option. For example, this would cap the maximum number of threads to 1: - -```bash -/opt/gitlab/embedded/service/gitlab-rails/ee/bin/sidekiq-cluster process_commit,post_receive -m 1 -``` diff --git a/doc/api/applications.md b/doc/api/applications.md index bcd119d1969..549828a983e 100644 --- a/doc/api/applications.md +++ b/doc/api/applications.md @@ -22,11 +22,12 @@ POST /applications Parameters: -| Attribute | Type | Required | Description | -|:---------------|:-------|:---------|:---------------------------------| -| `name` | string | yes | Name of the application. | -| `redirect_uri` | string | yes | Redirect URI of the application. | -| `scopes` | string | yes | Scopes of the application. | +| Attribute | Type | Required | Description | +|:---------------|:--------|:---------|:---------------------------------| +| `name` | string | yes | Name of the application. | +| `redirect_uri` | string | yes | Redirect URI of the application. | +| `scopes` | string | yes | Scopes of the application. | +| `confidential` | boolean | no | The application will be used where the client secret can be kept confidential. Native mobile apps and Single Page Apps are considered non-confidential. Defaults to `true` if not supplied | Example request: @@ -42,7 +43,8 @@ Example response: "application_id": "5832fc6e14300a0d962240a8144466eef4ee93ef0d218477e55f11cf12fc3737", "application_name": "MyApplication", "secret": "ee1dd64b6adc89cf7e2c23099301ccc2c61b441064e9324d963c46902a85ec34", - "callback_url": "http://redirect.uri" + "callback_url": "http://redirect.uri", + "confidential": true } ``` @@ -68,7 +70,8 @@ Example response: "id":1, "application_id": "5832fc6e14300a0d962240a8144466eef4ee93ef0d218477e55f11cf12fc3737", "application_name": "MyApplication", - "callback_url": "http://redirect.uri" + "callback_url": "http://redirect.uri", + "confidential": true } ] ``` diff --git a/doc/api/repositories.md b/doc/api/repositories.md index 4aff79c9c62..4bc28dd342f 100644 --- a/doc/api/repositories.md +++ b/doc/api/repositories.md @@ -128,7 +128,7 @@ curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.com/api/v4/pro ## Compare branches, tags or commits This endpoint can be accessed without authentication if the repository is -publicly accessible. +publicly accessible. Note that diffs could have an empty diff string if [diff limits](../development/diffs.html#diff-limits) are reached. ``` GET /projects/:id/repository/compare diff --git a/lib/api/applications.rb b/lib/api/applications.rb index 4e9843e17e8..70e6b8395d7 100644 --- a/lib/api/applications.rb +++ b/lib/api/applications.rb @@ -14,6 +14,9 @@ module API requires :name, type: String, desc: 'Application name' requires :redirect_uri, type: String, desc: 'Application redirect URI' requires :scopes, type: String, desc: 'Application scopes' + + optional :confidential, type: Boolean, default: true, + desc: 'Application will be used where the client secret is confidential' end post do application = Doorkeeper::Application.new(declared_params) diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 899418831bf..52ff819924b 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -1256,20 +1256,20 @@ module API end class Compare < Grape::Entity - expose :commit, using: Entities::Commit do |compare, options| - ::Commit.decorate(compare.commits, nil).last + expose :commit, using: Entities::Commit do |compare, _| + compare.commits.last end - expose :commits, using: Entities::Commit do |compare, options| - ::Commit.decorate(compare.commits, nil) + expose :commits, using: Entities::Commit do |compare, _| + compare.commits end - expose :diffs, using: Entities::Diff do |compare, options| - compare.diffs(limits: false).to_a + expose :diffs, using: Entities::Diff do |compare, _| + compare.diffs.diffs.to_a end - expose :compare_timeout do |compare, options| - compare.diffs.overflow? + expose :compare_timeout do |compare, _| + compare.diffs.diffs.overflow? end expose :same, as: :compare_same_ref @@ -1828,6 +1828,7 @@ module API expose :uid, as: :application_id expose :name, as: :application_name expose :redirect_uri, as: :callback_url + expose :confidential end # Use with care, this exposes the secret diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index b2f5def4048..aa6071e6099 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -316,7 +316,7 @@ module API def order_options_with_tie_breaker order_options = { params[:order_by] => params[:sort] } - order_options['id'] ||= 'desc' + order_options['id'] ||= params[:sort] || 'asc' order_options end diff --git a/lib/api/helpers/members_helpers.rb b/lib/api/helpers/members_helpers.rb index d06c59907b4..5cc435e6801 100644 --- a/lib/api/helpers/members_helpers.rb +++ b/lib/api/helpers/members_helpers.rb @@ -46,7 +46,7 @@ module API end def present_members(members) - present members, with: Entities::Member, current_user: current_user + present members, with: Entities::Member, current_user: current_user, show_seat_info: params[:show_seat_info] end end end diff --git a/lib/api/helpers/pagination_strategies.rb b/lib/api/helpers/pagination_strategies.rb index 5f63635297a..6bebb4bfeac 100644 --- a/lib/api/helpers/pagination_strategies.rb +++ b/lib/api/helpers/pagination_strategies.rb @@ -26,7 +26,7 @@ module API private def keyset_pagination_enabled? - params[:pagination] == 'keyset' && Feature.enabled?(:api_keyset_pagination, default_enabled: true) + params[:pagination] == 'keyset' end end end diff --git a/lib/api/members.rb b/lib/api/members.rb index e4df2f341c6..2e49b4be45c 100644 --- a/lib/api/members.rb +++ b/lib/api/members.rb @@ -19,6 +19,7 @@ module API params do optional :query, type: String, desc: 'A query string to search for members' optional :user_ids, type: Array[Integer], desc: 'Array of user ids to look up for membership' + optional :show_seat_info, type: Boolean, desc: 'Show seat information for members' use :optional_filter_params_ee use :pagination end @@ -37,6 +38,7 @@ module API params do optional :query, type: String, desc: 'A query string to search for members' optional :user_ids, type: Array[Integer], desc: 'Array of user ids to look up for membership' + optional :show_seat_info, type: Boolean, desc: 'Show seat information for members' use :pagination end diff --git a/lib/api/repositories.rb b/lib/api/repositories.rb index 4106a2cdf38..00473db1ff1 100644 --- a/lib/api/repositories.rb +++ b/lib/api/repositories.rb @@ -103,8 +103,13 @@ module API optional :straight, type: Boolean, desc: 'Comparison method, `true` for direct comparison between `from` and `to` (`from`..`to`), `false` to compare using merge base (`from`...`to`)', default: false end get ':id/repository/compare' do - compare = Gitlab::Git::Compare.new(user_project.repository.raw_repository, params[:from], params[:to], straight: params[:straight]) - present compare, with: Entities::Compare + compare = CompareService.new(user_project, params[:to]).execute(user_project, params[:from], straight: params[:straight]) + + if compare + present compare, with: Entities::Compare + else + not_found!("Ref") + end end desc 'Get repository contributors' do diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 788d4d43b70..e06754b9db5 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -18420,6 +18420,9 @@ msgstr "" msgid "The amount of seconds after which a request to get a secondary node status will time out." msgstr "" +msgid "The application will be used where the client secret can be kept confidential. Native mobile apps and Single Page Apps are considered non-confidential." +msgstr "" + msgid "The branch for this project has no active pipeline configuration." msgstr "" diff --git a/package.json b/package.json index f6007d831e5..c303d375d36 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "@gitlab/ui": "^8.18.0", "@gitlab/visual-review-tools": "1.5.1", "@sentry/browser": "^5.10.2", - "@sourcegraph/code-host-integration": "^0.0.18", + "@sourcegraph/code-host-integration": "0.0.21", "apollo-cache-inmemory": "^1.6.3", "apollo-client": "^2.6.4", "apollo-link": "^1.2.11", diff --git a/spec/controllers/admin/applications_controller_spec.rb b/spec/controllers/admin/applications_controller_spec.rb index 2f3c7da484b..63b28b2d993 100644 --- a/spec/controllers/admin/applications_controller_spec.rb +++ b/spec/controllers/admin/applications_controller_spec.rb @@ -40,7 +40,7 @@ describe Admin::ApplicationsController do describe 'POST #create' do it 'creates the application' do - create_params = attributes_for(:application, trusted: true) + create_params = attributes_for(:application, trusted: true, confidential: false) expect do post :create, params: { doorkeeper_application: create_params } @@ -60,16 +60,34 @@ describe Admin::ApplicationsController do expect(response).to render_template :new expect(assigns[:scopes]).to be_kind_of(Doorkeeper::OAuth::Scopes) end + + context 'when the params are for a confidential application' do + it 'creates a confidential application' do + create_params = attributes_for(:application, confidential: true) + + expect do + post :create, params: { doorkeeper_application: create_params } + end.to change { Doorkeeper::Application.count }.by(1) + + application = Doorkeeper::Application.last + + expect(response).to redirect_to(admin_application_path(application)) + expect(application).to have_attributes(create_params.except(:uid, :owner_type)) + end + end end describe 'PATCH #update' do it 'updates the application' do - patch :update, params: { id: application.id, doorkeeper_application: { redirect_uri: 'http://example.com/', trusted: true } } + doorkeeper_params = { redirect_uri: 'http://example.com/', trusted: true, confidential: false } + + patch :update, params: { id: application.id, doorkeeper_application: doorkeeper_params } application.reload expect(response).to redirect_to(admin_application_path(application)) - expect(application).to have_attributes(redirect_uri: 'http://example.com/', trusted: true) + expect(application) + .to have_attributes(redirect_uri: 'http://example.com/', trusted: true, confidential: false) end it 'renders the application form on errors' do @@ -78,5 +96,16 @@ describe Admin::ApplicationsController do expect(response).to render_template :edit expect(assigns[:scopes]).to be_kind_of(Doorkeeper::OAuth::Scopes) end + + context 'when updating the application to be confidential' do + it 'successfully sets the application to confidential' do + doorkeeper_params = { confidential: true } + + patch :update, params: { id: application.id, doorkeeper_application: doorkeeper_params } + + expect(response).to redirect_to(admin_application_path(application)) + expect(application).to be_confidential + end + end end end diff --git a/spec/controllers/groups/registry/repositories_controller_spec.rb b/spec/controllers/groups/registry/repositories_controller_spec.rb index 4129891914d..9463483b7b0 100644 --- a/spec/controllers/groups/registry/repositories_controller_spec.rb +++ b/spec/controllers/groups/registry/repositories_controller_spec.rb @@ -17,6 +17,8 @@ describe Groups::Registry::RepositoriesController do context 'GET #index' do context 'when container registry is enabled' do it 'show index page' do + expect(Gitlab::Tracking).not_to receive(:event) + get :index, params: { group_id: group } @@ -54,7 +56,8 @@ describe Groups::Registry::RepositoriesController do expect(Gitlab::Tracking).to receive(:event).with(anything, 'list_repositories', {}) get :index, params: { - group_id: group + group_id: group, + format: :json } end end diff --git a/spec/controllers/projects/registry/repositories_controller_spec.rb b/spec/controllers/projects/registry/repositories_controller_spec.rb index 192e4ce2e73..4e832a478af 100644 --- a/spec/controllers/projects/registry/repositories_controller_spec.rb +++ b/spec/controllers/projects/registry/repositories_controller_spec.rb @@ -35,6 +35,8 @@ describe Projects::Registry::RepositoriesController do end it 'successfully renders container repositories' do + expect(Gitlab::Tracking).not_to receive(:event) + go_to_index expect(response).to have_gitlab_http_status(:ok) @@ -43,7 +45,7 @@ describe Projects::Registry::RepositoriesController do it 'tracks the event' do expect(Gitlab::Tracking).to receive(:event).with(anything, 'list_repositories', {}) - go_to_index + go_to_index(format: :json) end it 'creates a root container repository' do diff --git a/spec/features/admin/admin_manage_applications_spec.rb b/spec/features/admin/admin_manage_applications_spec.rb index dd4d4b1a426..3f3d71e842c 100644 --- a/spec/features/admin/admin_manage_applications_spec.rb +++ b/spec/features/admin/admin_manage_applications_spec.rb @@ -21,18 +21,21 @@ RSpec.describe 'admin manage applications' do expect(page).to have_content('Application ID') expect(page).to have_content('Secret') expect(page).to have_content('Trusted Y') + expect(page).to have_content('Confidential Y') click_on 'Edit' expect(page).to have_content('Edit application') fill_in :doorkeeper_application_name, with: 'test_changed' uncheck :doorkeeper_application_trusted + uncheck :doorkeeper_application_confidential click_on 'Submit' expect(page).to have_content('test_changed') expect(page).to have_content('Application ID') expect(page).to have_content('Secret') expect(page).to have_content('Trusted N') + expect(page).to have_content('Confidential N') visit admin_applications_path page.within '.oauth-applications' do diff --git a/spec/features/profiles/user_manages_applications_spec.rb b/spec/features/profiles/user_manages_applications_spec.rb index 7a961855c92..668c4e8c784 100644 --- a/spec/features/profiles/user_manages_applications_spec.rb +++ b/spec/features/profiles/user_manages_applications_spec.rb @@ -20,16 +20,19 @@ describe 'User manages applications' do expect(page).to have_content 'Application: test' expect(page).to have_content 'Application ID' expect(page).to have_content 'Secret' + expect(page).to have_content 'Confidential Yes' click_on 'Edit' expect(page).to have_content 'Edit application' fill_in :doorkeeper_application_name, with: 'test_changed' + uncheck :doorkeeper_application_confidential click_on 'Save application' expect(page).to have_content 'test_changed' expect(page).to have_content 'Application ID' expect(page).to have_content 'Secret' + expect(page).to have_content 'Confidential No' visit applications_profile_path diff --git a/spec/fixtures/api/schemas/public_api/v4/members.json b/spec/fixtures/api/schemas/public_api/v4/members.json new file mode 100644 index 00000000000..38ad64ad061 --- /dev/null +++ b/spec/fixtures/api/schemas/public_api/v4/members.json @@ -0,0 +1,22 @@ +{ + "type": "array", + "items": { + "type": "object", + "properties" : { + "id": { "type": "integer" }, + "name": { "type": "string" }, + "username": { "type": "string" }, + "state": { "type": "string" }, + "avatar_url": { "type": ["string", "null"] }, + "web_url": { "type": ["string", "null"] }, + "access_level": { "type": "integer" }, + "expires_at": { "type": ["date", "null"] }, + "is_using_seat": { "type": "boolean" } + }, + "required": [ + "id", "name", "username", "state", + "web_url", "access_level", "expires_at" + ], + "additionalProperties": false + } +} diff --git a/spec/frontend/self_monitor/components/self_monitor_spec.js b/spec/frontend/self_monitor/components/self_monitor_spec.js index b95c7514047..50b97ae914d 100644 --- a/spec/frontend/self_monitor/components/self_monitor_spec.js +++ b/spec/frontend/self_monitor/components/self_monitor_spec.js @@ -11,7 +11,7 @@ describe('self monitor component', () => { beforeEach(() => { store = createStore({ projectEnabled: false, - selfMonitorProjectCreated: false, + selfMonitoringProjectExists: false, createSelfMonitoringProjectPath: '/create', deleteSelfMonitoringProjectPath: '/delete', }); @@ -69,7 +69,7 @@ describe('self monitor component', () => { it('renders the form description with a link', () => { store = createStore({ projectEnabled: true, - selfMonitorProjectCreated: true, + selfMonitoringProjectExists: true, createSelfMonitoringProjectPath: '/create', deleteSelfMonitoringProjectPath: '/delete', }); diff --git a/spec/frontend/self_monitor/store/actions_spec.js b/spec/frontend/self_monitor/store/actions_spec.js index 344dbf11954..0326ca6f415 100644 --- a/spec/frontend/self_monitor/store/actions_spec.js +++ b/spec/frontend/self_monitor/store/actions_spec.js @@ -140,7 +140,12 @@ describe('self monitor actions', () => { { type: types.SET_SHOW_ALERT, payload: true }, { type: types.SET_PROJECT_CREATED, payload: true }, ], - [], + [ + { + payload: true, + type: 'setSelfMonitor', + }, + ], done, ); }); diff --git a/spec/lib/api/helpers_spec.rb b/spec/lib/api/helpers_spec.rb index 81c4563feb6..9980f4d8e23 100644 --- a/spec/lib/api/helpers_spec.rb +++ b/spec/lib/api/helpers_spec.rb @@ -188,4 +188,46 @@ describe API::Helpers do subject.track_event('my_event', category: nil) end end + + describe '#order_options_with_tie_breaker' do + subject { Class.new.include(described_class).new.order_options_with_tie_breaker } + + before do + allow_any_instance_of(described_class).to receive(:params).and_return(params) + end + + context 'with non-id order given' do + context 'with ascending order' do + let(:params) { { order_by: 'name', sort: 'asc' } } + + it 'adds id based ordering with same direction as primary order' do + is_expected.to eq({ 'name' => 'asc', 'id' => 'asc' }) + end + end + + context 'with descending order' do + let(:params) { { order_by: 'name', sort: 'desc' } } + + it 'adds id based ordering with same direction as primary order' do + is_expected.to eq({ 'name' => 'desc', 'id' => 'desc' }) + end + end + end + + context 'with non-id order but no direction given' do + let(:params) { { order_by: 'name' } } + + it 'adds ID ASC order' do + is_expected.to eq({ 'name' => nil, 'id' => 'asc' }) + end + end + + context 'with id order given' do + let(:params) { { order_by: 'id', sort: 'asc' } } + + it 'does not add an additional order' do + is_expected.to eq({ 'id' => 'asc' }) + end + end + end end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 6f393d169a2..438ed6d83fa 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -25,6 +25,7 @@ describe User, :do_not_mock_admin_mode do describe 'associations' do it { is_expected.to have_one(:namespace) } it { is_expected.to have_one(:status) } + it { is_expected.to have_one(:max_access_level_membership) } it { is_expected.to have_many(:snippets).dependent(:destroy) } it { is_expected.to have_many(:members) } it { is_expected.to have_many(:project_members) } @@ -839,9 +840,36 @@ describe User, :do_not_mock_admin_mode do describe '#highest_role' do let(:user) { create(:user) } - let(:group) { create(:group) } + context 'with association :max_access_level_membership' do + let(:another_user) { create(:user) } + + before do + create(:project, group: group) do |project| + group.add_user(user, GroupMember::GUEST) + group.add_user(another_user, GroupMember::DEVELOPER) + end + + create(:project, group: create(:group)) do |project| + project.add_guest(another_user) + end + + create(:project, group: create(:group)) do |project| + project.add_maintainer(user) + end + end + + it 'returns the correct highest role' do + users = User.includes(:max_access_level_membership).where(id: [user.id, another_user.id]) + + expect(users.collect { |u| [u.id, u.highest_role] }).to contain_exactly( + [user.id, Gitlab::Access::MAINTAINER], + [another_user.id, Gitlab::Access::DEVELOPER] + ) + end + end + it 'returns NO_ACCESS if none has been set' do expect(user.highest_role).to eq(Gitlab::Access::NO_ACCESS) end diff --git a/spec/requests/api/applications_spec.rb b/spec/requests/api/applications_spec.rb index 438d5dbf018..d110751e661 100644 --- a/spec/requests/api/applications_spec.rb +++ b/spec/requests/api/applications_spec.rb @@ -21,6 +21,7 @@ describe API::Applications, :api do expect(json_response['application_id']).to eq application.uid expect(json_response['secret']).to eq application.secret expect(json_response['callback_url']).to eq application.redirect_uri + expect(json_response['confidential']).to eq application.confidential end it 'does not allow creating an application with the wrong redirect_uri format' do @@ -72,6 +73,16 @@ describe API::Applications, :api do expect(json_response).to be_a Hash expect(json_response['error']).to eq('scopes is missing') end + + it 'does not allow creating an application with confidential set to nil' do + expect do + post api('/applications', admin_user), params: { name: 'application_name', redirect_uri: 'http://application.url', scopes: '', confidential: nil } + end.not_to change { Doorkeeper::Application.count } + + expect(response).to have_gitlab_http_status(400) + expect(json_response).to be_a Hash + expect(json_response['message']['confidential'].first).to eq('is not included in the list') + end end context 'authorized user without authorization' do diff --git a/spec/requests/api/repositories_spec.rb b/spec/requests/api/repositories_spec.rb index ba301147d43..8bca458bece 100644 --- a/spec/requests/api/repositories_spec.rb +++ b/spec/requests/api/repositories_spec.rb @@ -362,6 +362,29 @@ describe API::Repositories do expect(json_response['diffs']).to be_empty expect(json_response['compare_same_ref']).to be_truthy end + + it "returns an empty string when the diff overflows" do + stub_const('Gitlab::Git::DiffCollection::DEFAULT_LIMITS', { max_files: 2, max_lines: 2 }) + + get api(route, current_user), params: { from: 'master', to: 'feature' } + + expect(response).to have_gitlab_http_status(200) + expect(json_response['commits']).to be_present + expect(json_response['diffs']).to be_present + expect(json_response['diffs'].first['diff']).to be_empty + end + + it "returns a 404 when from ref is unknown" do + get api(route, current_user), params: { from: 'unknown_ref', to: 'master' } + + expect(response).to have_gitlab_http_status(404) + end + + it "returns a 404 when to ref is unknown" do + get api(route, current_user), params: { from: 'master', to: 'unknown_ref' } + + expect(response).to have_gitlab_http_status(404) + end end context 'when unauthenticated', 'and project is public' do diff --git a/yarn.lock b/yarn.lock index 0f608dd5099..f3872f1c41a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -986,10 +986,10 @@ "@sentry/types" "5.10.0" tslib "^1.9.3" -"@sourcegraph/code-host-integration@^0.0.18": - version "0.0.18" - resolved "https://registry.yarnpkg.com/@sourcegraph/code-host-integration/-/code-host-integration-0.0.18.tgz#814467cdbc94bbfee5768193acf89fdf404ca949" - integrity sha512-PNKR6QI2MK17YJ4BBmWBz7SVRPIJZKbGkQpdB9jHsvQhdSxspdpWFaMu+HKeg96zpStdLhFOcDPn1wlKbdGy+w== +"@sourcegraph/code-host-integration@0.0.21": + version "0.0.21" + resolved "https://registry.yarnpkg.com/@sourcegraph/code-host-integration/-/code-host-integration-0.0.21.tgz#d536ccb3d9fda6d0c9d611ed6b80813265d8cb2f" + integrity sha512-HRBb6FO5+kc0JM6mAzhBGrDCuMdkGBjgdnKGnkW8B/FFKEtZEB6HI4ghGfY0eH01tFRis7snkZ4b3NSLjAbHew== "@types/anymatch@*": version "1.3.0" @@ -1153,21 +1153,6 @@ source-map "~0.6.1" vue-template-es2015-compiler "^1.9.0" -"@vue/component-compiler-utils@^3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@vue/component-compiler-utils/-/component-compiler-utils-3.0.0.tgz#d16fa26b836c06df5baaeb45f3d80afc47e35634" - integrity sha512-am+04/0UX7ektcmvhYmrf84BDVAD8afFOf4asZjN84q8xzxFclbk5x0MtxuKGfp+zjN5WWPJn3fjFAWtDdIGSw== - dependencies: - consolidate "^0.15.1" - hash-sum "^1.0.2" - lru-cache "^4.1.2" - merge-source-map "^1.1.0" - postcss "^7.0.14" - postcss-selector-parser "^5.0.0" - prettier "1.16.3" - source-map "~0.6.1" - vue-template-es2015-compiler "^1.9.0" - "@vue/component-compiler-utils@^3.1.0": version "3.1.1" resolved "https://registry.yarnpkg.com/@vue/component-compiler-utils/-/component-compiler-utils-3.1.1.tgz#d4ef8f80292674044ad6211e336a302e4d2a6575" @@ -2087,16 +2072,11 @@ bootstrap-vue@2.0.0-rc.27: portal-vue "^2.1.5" vue-functional-data-merge "^3.1.0" -bootstrap@4.3.1: +bootstrap@4.3.1, bootstrap@^4.3.1: version "4.3.1" resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-4.3.1.tgz#280ca8f610504d99d7b6b4bfc4b68cec601704ac" integrity sha512-rXqOmH1VilAt2DyPzluTi2blhk17bO7ef+zLLPlWvG494pDxcM234pJ8wTc/6R40UWizAIIMgxjvxZg5kmsbag== -bootstrap@^4.3.1: - version "4.4.1" - resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-4.4.1.tgz#8582960eea0c5cd2bede84d8b0baf3789c3e8b01" - integrity sha512-tbx5cHubwE6e2ZG7nqM3g/FZ5PQEDMWmMGNrCUBVRPHXTJaH7CBDdsLeu3eCh3B1tzAxTnAbtmrzvWEvT2NNEA== - boxen@^1.2.1: version "1.3.0" resolved "https://registry.yarnpkg.com/boxen/-/boxen-1.3.0.tgz#55c6c39a8ba58d9c61ad22cd877532deb665a20b" @@ -5520,12 +5500,7 @@ he@^1.1.0, he@^1.2.0: resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== -highlight.js@^9.13.1: - version "9.18.0" - resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-9.18.0.tgz#6b1763cfcd53744313bd3f31f1210f7beb962c79" - integrity sha512-A97kI1KAUzKoAiEoaGcf2O9YPS8nbDTCRFokaaeBhnqjQTvbAuAJrQMm21zw8s8xzaMtCQBtgbyGXLGxdxQyqQ== - -highlight.js@~9.13.0: +highlight.js@^9.13.1, highlight.js@~9.13.0: version "9.13.1" resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-9.13.1.tgz#054586d53a6863311168488a0f58d6c505ce641e" integrity sha512-Sc28JNQNDzaH6PORtRLMvif9RSn1mYuOoX3omVjnb0+HbpPygU2ALBI0R/wsiqCb4/fcp07Gdo8g+fhtFrQl6A== @@ -6803,18 +6778,7 @@ js-base64@^2.1.8: resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.5.1.tgz#1efa39ef2c5f7980bb1784ade4a8af2de3291121" integrity sha512-M7kLczedRMYX4L8Mdh4MzyAMM9O5osx+4FcOQuTvr3A9F2D9S5JXheN0ewNbrvK2UatkTRhL5ejGmGSjNMiZuw== -js-beautify@^1.6.12: - version "1.10.2" - resolved "https://registry.yarnpkg.com/js-beautify/-/js-beautify-1.10.2.tgz#88c9099cd6559402b124cfab18754936f8a7b178" - integrity sha512-ZtBYyNUYJIsBWERnQP0rPN9KjkrDfJcMjuVGcvXOUJrD1zmOGwhRwQ4msG+HJ+Ni/FA7+sRQEMYVzdTQDvnzvQ== - dependencies: - config-chain "^1.1.12" - editorconfig "^0.15.3" - glob "^7.1.3" - mkdirp "~0.5.1" - nopt "~4.0.1" - -js-beautify@^1.8.8: +js-beautify@^1.6.12, js-beautify@^1.8.8: version "1.10.3" resolved "https://registry.yarnpkg.com/js-beautify/-/js-beautify-1.10.3.tgz#c73fa10cf69d3dfa52d8ed624f23c64c0a6a94c1" integrity sha512-wfk/IAWobz1TfApSdivH5PJ0miIHgDoYb1ugSqHcODPmaYu46rYe5FVuIEkhjg8IQiv6rDNPyhsqbsohI/C2vQ== @@ -8836,12 +8800,7 @@ pofile@^1: resolved "https://registry.yarnpkg.com/pofile/-/pofile-1.0.11.tgz#35aff58c17491d127a07336d5522ebc9df57c954" integrity sha512-Vy9eH1dRD9wHjYt/QqXcTz+RnX/zg53xK+KljFSX30PvdDMb2z+c6uDUeblUGqqJgz3QFsdlA0IJvHziPmWtQg== -popper.js@^1.14.7: - version "1.15.0" - resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.15.0.tgz#5560b99bbad7647e9faa475c6b8056621f5a4ff2" - integrity sha512-w010cY1oCUmI+9KwwlWki+r5jxKfTFDVoadl7MSrIujHU5MJ5OR6HTDj6Xo8aoR/QsA56x8jKjA59qGH4ELtrA== - -popper.js@^1.15.0: +popper.js@^1.14.7, popper.js@^1.15.0: version "1.16.0" resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.16.0.tgz#2e1816bcbbaa518ea6c2e15a466f4cb9c6e2fbb3" integrity sha512-+G+EkOPoE5S/zChTpmBSSDYmhXJ5PsW8eMhH8cP/CQHMFPBG/kC9Y5IIw6qNYgdJ+/COf0ddY2li28iHaZRSjw== @@ -9042,16 +9001,11 @@ prettier@1.16.3: resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.16.3.tgz#8c62168453badef702f34b45b6ee899574a6a65d" integrity sha512-kn/GU6SMRYPxUakNXhpP0EedT/KmaPzr0H5lIsDogrykbaxOpOfAFfk5XA7DZrJyMAv1wlMV3CPcZruGXVVUZw== -prettier@1.18.2: +prettier@1.18.2, prettier@^1.18.2: version "1.18.2" resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.18.2.tgz#6823e7c5900017b4bd3acf46fe9ac4b4d7bda9ea" integrity sha512-OeHeMc0JhFE9idD4ZdtNibzY0+TPHSpSSb9h8FqtP+YnoZZ1sl8Vc9b1sasjfymH3SonAF4QcA2+mzHPhMvIiw== -prettier@^1.18.2: - version "1.19.1" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb" - integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew== - pretty-format@^24.8.0: version "24.8.0" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-24.8.0.tgz#8dae7044f58db7cb8be245383b565a963e3c27f2" @@ -11759,7 +11713,7 @@ vue-jest@^4.0.0-beta.2: source-map "^0.5.6" ts-jest "^23.10.5" -vue-loader@^15.4.2: +vue-loader@^15.4.2, vue-loader@^15.7.1: version "15.8.3" resolved "https://registry.yarnpkg.com/vue-loader/-/vue-loader-15.8.3.tgz#857cb9e30eb5fc25e66db48dce7e4f768602a23c" integrity sha512-yFksTFbhp+lxlm92DrKdpVIWMpranXnTEuGSc0oW+Gk43M9LWaAmBTnfj5+FCdve715mTHvo78IdaXf5TbiTJg== @@ -11770,17 +11724,6 @@ vue-loader@^15.4.2: vue-hot-reload-api "^2.3.0" vue-style-loader "^4.1.0" -vue-loader@^15.7.1: - version "15.7.1" - resolved "https://registry.yarnpkg.com/vue-loader/-/vue-loader-15.7.1.tgz#6ccacd4122aa80f69baaac08ff295a62e3aefcfd" - integrity sha512-fwIKtA23Pl/rqfYP5TSGK7gkEuLhoTvRYW+TU7ER3q9GpNLt/PjG5NLv3XHRDiTg7OPM1JcckBgds+VnAc+HbA== - dependencies: - "@vue/component-compiler-utils" "^3.0.0" - hash-sum "^1.0.2" - loader-utils "^1.1.0" - vue-hot-reload-api "^2.3.0" - vue-style-loader "^4.1.0" - vue-router@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-3.0.2.tgz#dedc67afe6c4e2bc25682c8b1c2a8c0d7c7e56be" |