diff options
Diffstat (limited to 'app')
-rw-r--r-- | app/assets/javascripts/behaviors/markdown/render_observability.js | 45 | ||||
-rw-r--r-- | app/assets/javascripts/pages/projects/project.js | 3 | ||||
-rw-r--r-- | app/assets/javascripts/repository/index.js | 9 | ||||
-rw-r--r-- | app/assets/javascripts/repository/utils/ref_switcher_utils.js | 30 | ||||
-rw-r--r-- | app/controllers/concerns/confirm_email_warning.rb | 14 | ||||
-rw-r--r-- | app/controllers/projects/blob_controller.rb | 10 | ||||
-rw-r--r-- | app/controllers/projects/refs_controller.rb | 2 | ||||
-rw-r--r-- | app/controllers/projects/tree_controller.rb | 9 | ||||
-rw-r--r-- | app/controllers/projects_controller.rb | 10 | ||||
-rw-r--r-- | app/finders/environments/environment_names_finder.rb | 11 | ||||
-rw-r--r-- | app/finders/notes_finder.rb | 8 | ||||
-rw-r--r-- | app/models/hooks/web_hook.rb | 18 | ||||
-rw-r--r-- | app/models/project_feature.rb | 3 | ||||
-rw-r--r-- | app/policies/project_policy.rb | 1 | ||||
-rw-r--r-- | app/services/merge_requests/push_options_handler_service.rb | 10 | ||||
-rw-r--r-- | app/views/explore/projects/page_out_of_bounds.html.haml | 2 | ||||
-rw-r--r-- | app/views/projects/tree/_tree_header.html.haml | 2 |
17 files changed, 132 insertions, 55 deletions
diff --git a/app/assets/javascripts/behaviors/markdown/render_observability.js b/app/assets/javascripts/behaviors/markdown/render_observability.js index 704d85cf22e..d5d46c10efd 100644 --- a/app/assets/javascripts/behaviors/markdown/render_observability.js +++ b/app/assets/javascripts/behaviors/markdown/render_observability.js @@ -7,23 +7,36 @@ export function getFrameSrc(url) { } const mountVueComponent = (element) => { - const url = [element.dataset.frameUrl]; + const { frameUrl, observabilityUrl } = element.dataset; - return new Vue({ - el: element, - render(h) { - return h('iframe', { - style: { - height: '366px', - width: '768px', - }, - attrs: { - src: getFrameSrc(url), - frameBorder: '0', - }, - }); - }, - }); + try { + if ( + !observabilityUrl || + !frameUrl || + new URL(frameUrl)?.host !== new URL(observabilityUrl).host + ) + return; + + // eslint-disable-next-line no-new + new Vue({ + el: element, + render(h) { + return h('iframe', { + style: { + height: '366px', + width: '768px', + }, + attrs: { + src: getFrameSrc(frameUrl), + frameBorder: '0', + }, + }); + }, + }); + } catch (e) { + // eslint-disable-next-line no-console + console.error(e); + } }; export default function renderObservability(elements) { diff --git a/app/assets/javascripts/pages/projects/project.js b/app/assets/javascripts/pages/projects/project.js index 4c9eb830ff6..27659348dcc 100644 --- a/app/assets/javascripts/pages/projects/project.js +++ b/app/assets/javascripts/pages/projects/project.js @@ -118,9 +118,10 @@ export default class Project { const urlParams = { [fieldName]: ref }; if (params.group === BRANCH_GROUP_NAME) { urlParams.ref_type = BRANCH_REF_TYPE; - } else { + } else if (params.group === TAG_GROUP_NAME) { urlParams.ref_type = TAG_REF_TYPE; } + link.href = mergeUrlParams(urlParams, linkTarget); } diff --git a/app/assets/javascripts/repository/index.js b/app/assets/javascripts/repository/index.js index e5d22f50d72..0f6b159ffc5 100644 --- a/app/assets/javascripts/repository/index.js +++ b/app/assets/javascripts/repository/index.js @@ -2,7 +2,7 @@ import { GlButton } from '@gitlab/ui'; import Vue from 'vue'; import Vuex from 'vuex'; import { parseBoolean } from '~/lib/utils/common_utils'; -import { escapeFileUrl, visitUrl } from '~/lib/utils/url_utility'; +import { joinPaths, escapeFileUrl, visitUrl } from '~/lib/utils/url_utility'; import { __ } from '~/locale'; import initWebIdeLink from '~/pages/projects/shared/web_ide_link'; import PerformancePlugin from '~/performance/vue_performance_plugin'; @@ -119,7 +119,7 @@ export default function setupVueRepositoryList() { if (!refSwitcherEl) return false; - const { projectId, projectRootPath } = refSwitcherEl.dataset; + const { projectId, projectRootPath, refType } = refSwitcherEl.dataset; return new Vue({ el: refSwitcherEl, @@ -127,11 +127,12 @@ export default function setupVueRepositoryList() { return createElement(RefSelector, { props: { projectId, - value: ref, + value: refType ? joinPaths('refs', refType, ref) : ref, + useSymbolicRefNames: true, }, on: { input(selectedRef) { - visitUrl(generateRefDestinationPath(projectRootPath, selectedRef)); + visitUrl(generateRefDestinationPath(projectRootPath, ref, selectedRef)); }, }, }); diff --git a/app/assets/javascripts/repository/utils/ref_switcher_utils.js b/app/assets/javascripts/repository/utils/ref_switcher_utils.js index f296b5e9b4a..fc0d521ad54 100644 --- a/app/assets/javascripts/repository/utils/ref_switcher_utils.js +++ b/app/assets/javascripts/repository/utils/ref_switcher_utils.js @@ -15,22 +15,30 @@ const NAMESPACE_TARGET_REGEX = /(\/-\/(blob|tree))\/.*?\/(.*)/; * @param {string} projectRootPath - The root path for a project. * @param {string} selectedRef - The selected ref from the ref dropdown. */ -export function generateRefDestinationPath(projectRootPath, selectedRef) { - const currentPath = window.location.pathname; - const encodedHash = '%23'; + +export function generateRefDestinationPath(projectRootPath, ref, selectedRef) { + const url = new URL(window.location.href); + const currentPath = url.pathname; + let refType = null; let namespace = '/-/tree'; let target; + let actualRef = selectedRef; + + const matches = selectedRef.match(/^refs\/(heads|tags)\/(.+)/); + if (matches) { + [, refType, actualRef] = matches; + } + if (refType) { + url.searchParams.set('ref_type', refType); + } else { + url.searchParams.delete('ref_type'); + } + const match = NAMESPACE_TARGET_REGEX.exec(currentPath); if (match) { [, namespace, , target] = match; } + url.pathname = joinPaths(projectRootPath, namespace, actualRef, target); - const destinationPath = joinPaths( - projectRootPath, - namespace, - encodeURI(selectedRef).replace(/#/g, encodedHash), - target, - ); - - return `${destinationPath}${window.location.hash}`; + return url.toString(); } diff --git a/app/controllers/concerns/confirm_email_warning.rb b/app/controllers/concerns/confirm_email_warning.rb index ec5140bf223..2711c823275 100644 --- a/app/controllers/concerns/confirm_email_warning.rb +++ b/app/controllers/concerns/confirm_email_warning.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true module ConfirmEmailWarning + include Gitlab::Utils::StrongMemoize extend ActiveSupport::Concern included do @@ -17,11 +18,9 @@ module ConfirmEmailWarning return unless current_user return if current_user.confirmed? - email = current_user.unconfirmed_email || current_user.email - flash.now[:warning] = format( confirm_warning_message, - email: email, + email: email_to_display, resend_link: view_context.link_to(_('Resend it'), user_confirmation_path(user: { email: email }), method: :post), update_link: view_context.link_to(_('Update it'), profile_path) ).html_safe @@ -29,7 +28,16 @@ module ConfirmEmailWarning private + def email + current_user.unconfirmed_email || current_user.email + end + strong_memoize_attr :email + def confirm_warning_message _("Please check your email (%{email}) to verify that you own this address and unlock the power of CI/CD. Didn't receive it? %{resend_link}. Wrong email address? %{update_link}.") end + + def email_to_display + html_escape(email) + end end diff --git a/app/controllers/projects/blob_controller.rb b/app/controllers/projects/blob_controller.rb index 4eda76f4f21..dd2f980e880 100644 --- a/app/controllers/projects/blob_controller.rb +++ b/app/controllers/projects/blob_controller.rb @@ -31,6 +31,7 @@ class Projects::BlobController < Projects::ApplicationController before_action :authorize_edit_tree!, only: [:new, :create, :update, :destroy] before_action :commit, except: [:new, :create] + before_action :check_for_ambiguous_ref, only: [:show] before_action :blob, except: [:new, :create] before_action :require_branch_head, only: [:edit, :update] before_action :editor_variables, except: [:show, :preview, :diff] @@ -145,6 +146,15 @@ class Projects::BlobController < Projects::ApplicationController end end + def check_for_ambiguous_ref + @ref_type = ref_type + + if @ref_type == ExtractsRef::BRANCH_REF_TYPE && ambiguous_ref?(@project, @ref) + branch = @project.repository.find_branch(@ref) + redirect_to project_blob_path(@project, File.join(branch.target, @path)) + end + end + def commit @commit ||= @repository.commit(@ref) diff --git a/app/controllers/projects/refs_controller.rb b/app/controllers/projects/refs_controller.rb index 8ac6d872aae..0b52d03ab95 100644 --- a/app/controllers/projects/refs_controller.rb +++ b/app/controllers/projects/refs_controller.rb @@ -22,7 +22,7 @@ class Projects::RefsController < Projects::ApplicationController when "tree" project_tree_path(@project, @id) when "blob" - project_blob_path(@project, @id) + project_blob_path(@project, @id, ref_type: ref_type) when "graph" if Feature.enabled?(:use_ref_type_parameter, @project) project_network_path(@project, @id, ref_type: ref_type) diff --git a/app/controllers/projects/tree_controller.rb b/app/controllers/projects/tree_controller.rb index 737a6290431..1f7912e15df 100644 --- a/app/controllers/projects/tree_controller.rb +++ b/app/controllers/projects/tree_controller.rb @@ -28,6 +28,15 @@ class Projects::TreeController < Projects::ApplicationController def show return render_404 unless @commit + @ref_type = ref_type + if @ref_type == BRANCH_REF_TYPE && ambiguous_ref?(@project, @ref) + branch = @project.repository.find_branch(@ref) + if branch + redirect_to project_tree_path(@project, branch.target) + return + end + end + if tree.entries.empty? if @repository.blob_at(@commit.id, @path) redirect_to project_blob_path(@project, File.join(@ref, @path)) diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index ee2c268ff33..ed7c163c108 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -172,11 +172,19 @@ class ProjectsController < Projects::ApplicationController flash.now[:alert] = _("Project '%{project_name}' queued for deletion.") % { project_name: @project.name } end + if ambiguous_ref?(@project, @ref) + branch = @project.repository.find_branch(@ref) + + # The files view would render a ref other than the default branch + # This redirect can be removed once the view is fixed + redirect_to(project_tree_path(@project, branch.target), alert: _("The default branch of this project clashes with another ref")) + return + end + respond_to do |format| format.html do @notification_setting = current_user.notification_settings_for(@project) if current_user @project = @project.present(current_user: current_user) - render_landing_page end diff --git a/app/finders/environments/environment_names_finder.rb b/app/finders/environments/environment_names_finder.rb index d4928f0fc84..ffb689f45e2 100644 --- a/app/finders/environments/environment_names_finder.rb +++ b/app/finders/environments/environment_names_finder.rb @@ -32,18 +32,9 @@ module Environments end def namespace_environments - # We assume reporter access is needed for the :read_environment permission - # here. This expection is also present in - # IssuableFinder::Params#min_access_level, which is used for filtering out - # merge requests that don't have the right permissions. - # - # We use this approach so we don't need to load every project into memory - # just to verify if we can see their environments. Doing so would not be - # efficient, and possibly mess up pagination if certain projects are not - # meant to be visible. projects = project_or_group .all_projects - .public_or_visible_to_user(current_user, Gitlab::Access::REPORTER) + .filter_by_feature_visibility(:environments, current_user) Environment.for_project(projects) end diff --git a/app/finders/notes_finder.rb b/app/finders/notes_finder.rb index c542ffbce7e..ea16bc01029 100644 --- a/app/finders/notes_finder.rb +++ b/app/finders/notes_finder.rb @@ -30,6 +30,7 @@ class NotesFinder notes = init_collection notes = since_fetch_at(notes) notes = notes.with_notes_filter(@params[:notes_filter]) if notes_filter? + notes = redact_internal(notes) sort(notes) end @@ -181,6 +182,13 @@ class NotesFinder notes.order_by(sort) end + + def redact_internal(notes) + subject = @project || target + return notes if Ability.allowed?(@current_user, :reporter_access, subject) + + notes.not_internal + end end NotesFinder.prepend_mod_with('NotesFinder') diff --git a/app/models/hooks/web_hook.rb b/app/models/hooks/web_hook.rb index 49418cda3ac..a787eb1d5f0 100644 --- a/app/models/hooks/web_hook.rb +++ b/app/models/hooks/web_hook.rb @@ -41,7 +41,7 @@ class WebHook < ApplicationRecord after_initialize :initialize_url_variables before_validation :reset_token - before_validation :reset_url_variables, unless: ->(hook) { hook.is_a?(ServiceHook) } + before_validation :reset_url_variables, unless: ->(hook) { hook.is_a?(ServiceHook) }, on: :update before_validation :set_branch_filter_nil, if: :branch_filter_strategy_all_branches? validates :push_events_branch_filter, untrusted_regexp: true, if: :branch_filter_strategy_regex? validates :push_events_branch_filter, "web_hooks/wildcard_branch_filter": true, if: :branch_filter_strategy_wildcard? @@ -189,7 +189,7 @@ class WebHook < ApplicationRecord # See app/validators/json_schemas/web_hooks_url_variables.json VARIABLE_REFERENCE_RE = /\{([A-Za-z]+[0-9]*(?:[._-][A-Za-z0-9]+)*)\}/.freeze - def interpolated_url + def interpolated_url(url = self.url, url_variables = self.url_variables) return url unless url.include?('{') vars = url_variables @@ -215,7 +215,19 @@ class WebHook < ApplicationRecord end def reset_url_variables - self.url_variables = {} if url_changed? && !encrypted_url_variables_changed? + interpolated_url_was = interpolated_url(decrypt_url_was, url_variables_were) + + return if url_variables_were.empty? || interpolated_url_was == interpolated_url + + self.url_variables = {} if url_changed? && url_variables_were.to_a.intersection(url_variables.to_a).any? + end + + def decrypt_url_was + self.class.decrypt_url(encrypted_url_was, iv: Base64.decode64(encrypted_url_iv_was)) + end + + def url_variables_were + self.class.decrypt_url_variables(encrypted_url_variables_was, iv: encrypted_url_variables_iv_was) end def next_failure_count diff --git a/app/models/project_feature.rb b/app/models/project_feature.rb index 11f4a3f3b6f..d7bb9fa18ae 100644 --- a/app/models/project_feature.rb +++ b/app/models/project_feature.rb @@ -36,7 +36,8 @@ class ProjectFeature < ApplicationRecord merge_requests: Gitlab::Access::REPORTER, metrics_dashboard: Gitlab::Access::REPORTER, container_registry: Gitlab::Access::REPORTER, - package_registry: Gitlab::Access::REPORTER + package_registry: Gitlab::Access::REPORTER, + environments: Gitlab::Access::REPORTER }.freeze PRIVATE_FEATURES_MIN_ACCESS_LEVEL_FOR_PRIVATE_PROJECT = { repository: Gitlab::Access::REPORTER }.freeze diff --git a/app/policies/project_policy.rb b/app/policies/project_policy.rb index b85a57f81cd..cd05cc1763d 100644 --- a/app/policies/project_policy.rb +++ b/app/policies/project_policy.rb @@ -404,7 +404,6 @@ class ProjectPolicy < BasePolicy end rule { can?(:metrics_dashboard) }.policy do - enable :read_prometheus enable :read_deployment end diff --git a/app/services/merge_requests/push_options_handler_service.rb b/app/services/merge_requests/push_options_handler_service.rb index 711978dc3f7..66af1c087ed 100644 --- a/app/services/merge_requests/push_options_handler_service.rb +++ b/app/services/merge_requests/push_options_handler_service.rb @@ -54,7 +54,15 @@ module MergeRequests end def validate_service - errors << 'User is required' if current_user.nil? + if current_user.nil? + errors << 'User is required' + return + end + + unless current_user&.can?(:read_code, target_project) + errors << 'User access was denied' + return + end unless target_project.merge_requests_enabled? errors << "Merge requests are not enabled for project #{target_project.full_path}" diff --git a/app/views/explore/projects/page_out_of_bounds.html.haml b/app/views/explore/projects/page_out_of_bounds.html.haml index ef5ee2c679e..e13768a3ccb 100644 --- a/app/views/explore/projects/page_out_of_bounds.html.haml +++ b/app/views/explore/projects/page_out_of_bounds.html.haml @@ -18,5 +18,5 @@ %h5= _("Maximum page reached") %p= _("Sorry, you have exceeded the maximum browsable page number. Please use the API to explore further.") - = render Pajamas::ButtonComponent.new(href: request.params.merge(page: @max_page_number)) do + = render Pajamas::ButtonComponent.new(href: safe_params.merge(page: @max_page_number)) do = _("Back to page %{number}") % { number: @max_page_number } diff --git a/app/views/projects/tree/_tree_header.html.haml b/app/views/projects/tree/_tree_header.html.haml index fd807350245..543cbc4e4e4 100644 --- a/app/views/projects/tree/_tree_header.html.haml +++ b/app/views/projects/tree/_tree_header.html.haml @@ -2,7 +2,7 @@ .tree-ref-container.gl-display-flex.mb-2.mb-md-0 .tree-ref-holder - #js-tree-ref-switcher{ data: { project_id: @project.id, project_root_path: project_path(@project) } } + #js-tree-ref-switcher{ data: { project_id: @project.id, ref_type: @ref_type.to_s, project_root_path: project_path(@project) } } #js-repo-breadcrumb{ data: breadcrumb_data_attributes } |