Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
52af12cfec
commit
386339e38e
|
@ -1 +1 @@
|
|||
034cc7332fc1ebf67599f7f9e98e1588bc6d1823
|
||||
4ba8618078d9107d52c0d735f76286ab0b113a8a
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Resolvers
|
||||
module Users
|
||||
class ParticipantsResolver < BaseResolver
|
||||
type Types::UserType.connection_type, null: true
|
||||
|
||||
def resolve(**args)
|
||||
object.visible_participants(current_user)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -80,7 +80,8 @@ module Types
|
|||
description: 'Relative position of the issue (used for positioning in epic tree and issue boards).'
|
||||
|
||||
field :participants, Types::UserType.connection_type, null: true, complexity: 5,
|
||||
description: 'List of participants in the issue.'
|
||||
description: 'List of participants in the issue.',
|
||||
resolver: Resolvers::Users::ParticipantsResolver
|
||||
field :emails_disabled, GraphQL::Types::Boolean, null: false,
|
||||
method: :project_emails_disabled?,
|
||||
description: 'Indicates if a project has email notifications disabled: `true` if email notifications are disabled.'
|
||||
|
|
|
@ -148,7 +148,8 @@ module Types
|
|||
field :author, Types::UserType, null: true,
|
||||
description: 'User who created this merge request.'
|
||||
field :participants, Types::UserType.connection_type, null: true, complexity: 15,
|
||||
description: 'Participants in the merge request. This includes the author, assignees, reviewers, and users mentioned in notes.'
|
||||
description: 'Participants in the merge request. This includes the author, assignees, reviewers, and users mentioned in notes.',
|
||||
resolver: Resolvers::Users::ParticipantsResolver
|
||||
field :subscribed, GraphQL::Types::Boolean, method: :subscribed?, null: false, complexity: 5,
|
||||
description: 'Indicates if the currently logged in user is subscribed to this merge request.'
|
||||
field :labels, Types::LabelType.connection_type, null: true, complexity: 5,
|
||||
|
|
|
@ -21,7 +21,7 @@ class ApplicationSetting < ApplicationRecord
|
|||
|
||||
add_authentication_token_field :runners_registration_token, encrypted: -> { Feature.enabled?(:application_settings_tokens_optional_encryption) ? :optional : :required }
|
||||
add_authentication_token_field :health_check_access_token
|
||||
add_authentication_token_field :static_objects_external_storage_auth_token
|
||||
add_authentication_token_field :static_objects_external_storage_auth_token, encrypted: :optional
|
||||
|
||||
belongs_to :self_monitoring_project, class_name: "Project", foreign_key: 'instance_administration_project_id'
|
||||
belongs_to :push_rule
|
||||
|
|
|
@ -363,6 +363,14 @@ module ApplicationSettingImplementation
|
|||
super(levels&.map { |level| Gitlab::VisibilityLevel.level_value(level) })
|
||||
end
|
||||
|
||||
def static_objects_external_storage_auth_token=(token)
|
||||
if token.present?
|
||||
set_static_objects_external_storage_auth_token(token)
|
||||
else
|
||||
self.static_objects_external_storage_auth_token_encrypted = nil
|
||||
end
|
||||
end
|
||||
|
||||
def performance_bar_allowed_group
|
||||
Group.find_by_id(performance_bar_allowed_group_id)
|
||||
end
|
||||
|
|
|
@ -59,7 +59,7 @@ module Ci
|
|||
has_one :runner_session, class_name: 'Ci::BuildRunnerSession', validate: true, inverse_of: :build
|
||||
has_one :trace_metadata, class_name: 'Ci::BuildTraceMetadata', inverse_of: :build
|
||||
|
||||
has_many :terraform_state_versions, class_name: 'Terraform::StateVersion', dependent: :nullify, inverse_of: :build, foreign_key: :ci_build_id # rubocop:disable Cop/ActiveRecordDependent
|
||||
has_many :terraform_state_versions, class_name: 'Terraform::StateVersion', inverse_of: :build, foreign_key: :ci_build_id
|
||||
|
||||
accepts_nested_attributes_for :runner_session, update_only: true
|
||||
accepts_nested_attributes_for :job_variables
|
||||
|
|
|
@ -60,6 +60,15 @@ module Participable
|
|||
filtered_participants_hash[user]
|
||||
end
|
||||
|
||||
# Returns only participants visible for the user
|
||||
#
|
||||
# Returns an Array of User instances.
|
||||
def visible_participants(user)
|
||||
return participants(user) unless Feature.enabled?(:verify_participants_access, project, default_enabled: :yaml)
|
||||
|
||||
filter_by_ability(raw_participants(user, verify_access: true))
|
||||
end
|
||||
|
||||
# Checks if the user is a participant in a discussion.
|
||||
#
|
||||
# This method processes attributes of objects in breadth-first order.
|
||||
|
@ -84,8 +93,7 @@ module Participable
|
|||
end
|
||||
end
|
||||
|
||||
def raw_participants(current_user = nil)
|
||||
current_user ||= author
|
||||
def raw_participants(current_user = nil, verify_access: false)
|
||||
ext = Gitlab::ReferenceExtractor.new(project, current_user)
|
||||
participants = Set.new
|
||||
process = [self]
|
||||
|
@ -97,6 +105,8 @@ module Participable
|
|||
when User
|
||||
participants << source
|
||||
when Participable
|
||||
next unless !verify_access || source_visible_to_user?(source, current_user)
|
||||
|
||||
source.class.participant_attrs.each do |attr|
|
||||
if attr.respond_to?(:call)
|
||||
source.instance_exec(current_user, ext, &attr)
|
||||
|
@ -116,6 +126,10 @@ module Participable
|
|||
participants.merge(ext.users)
|
||||
end
|
||||
|
||||
def source_visible_to_user?(source, user)
|
||||
Ability.allowed?(user, "read_#{source.model_name.element}".to_sym, source)
|
||||
end
|
||||
|
||||
def filter_by_ability(participants)
|
||||
case self
|
||||
when PersonalSnippet
|
||||
|
|
|
@ -14,7 +14,7 @@ module Ci
|
|||
Ci::JobVariable.bulk_insert!(variables)
|
||||
|
||||
success
|
||||
rescue SizeLimitError, ParserError, ActiveRecord::RecordInvalid => error
|
||||
rescue SizeLimitError, ParserError, ActiveRecord::RecordInvalid, ActiveRecord::RecordNotUnique => error
|
||||
Gitlab::ErrorTracking.track_exception(error, job_id: artifact.job_id)
|
||||
error(error.message, :bad_request)
|
||||
end
|
||||
|
|
|
@ -1,42 +0,0 @@
|
|||
- can_create_issue = show_new_issue_link?(@project)
|
||||
- can_create_project_snippet = can?(current_user, :create_snippet, @project)
|
||||
- can_push_code = can?(current_user, :push_code, @project)
|
||||
- create_mr_from_new_fork = can?(current_user, :fork_project, @project) && can?(current_user, :create_merge_request_in, @project)
|
||||
- merge_project = merge_request_source_project_for_project(@project)
|
||||
|
||||
- show_menu = can_create_issue || can_create_project_snippet || can_push_code || create_mr_from_new_fork || merge_project
|
||||
|
||||
- if show_menu
|
||||
.project-action-button.dropdown.inline<
|
||||
%a.btn.btn-default.gl-button.dropdown-toggle.has-tooltip.qa-create-new-dropdown{ href: '#', title: _('Create new...'), 'data-toggle' => 'dropdown', 'data-container' => 'body', 'aria-label' => _('Create new...'), 'data-display' => 'static' }
|
||||
= sprite_icon('plus', css_class: 'gl-icon')
|
||||
= sprite_icon("chevron-down", css_class: 'gl-icon')
|
||||
%ul.dropdown-menu.dropdown-menu-right.project-home-dropdown
|
||||
- if can_create_issue || merge_project || can_create_project_snippet
|
||||
%li.dropdown-header= _('This project')
|
||||
|
||||
- if can_create_issue
|
||||
%li= link_to _('New issue'), new_project_issue_path(@project)
|
||||
|
||||
- if merge_project
|
||||
%li= link_to _('New merge request'), project_new_merge_request_path(merge_project)
|
||||
|
||||
- if can_create_project_snippet
|
||||
%li= link_to _('New snippet'), new_project_snippet_path(@project)
|
||||
|
||||
- if can_push_code
|
||||
%li.dropdown-header= _('This repository')
|
||||
|
||||
- if can_push_code
|
||||
%li.qa-new-file-option= link_to _('New file'), project_new_blob_path(@project, @project.default_branch_or_main)
|
||||
- unless @project.empty_repo?
|
||||
%li= link_to _('New branch'), new_project_branch_path(@project)
|
||||
%li= link_to _('New tag'), new_project_tag_path(@project)
|
||||
- elsif can_collaborate_with_project?(@project)
|
||||
%li= link_to _('New file'), project_new_blob_path(@project, @project.default_branch_or_main)
|
||||
- elsif create_mr_from_new_fork
|
||||
- continue_params = { to: project_new_blob_path(@project, @project.default_branch_or_main),
|
||||
notice: edit_in_new_fork_notice,
|
||||
notice_now: edit_in_new_fork_notice_now }
|
||||
- fork_path = project_forks_path(@project, namespace_key: current_user.namespace.id, continue: continue_params)
|
||||
%li= link_to _('New file'), fork_path, method: :post
|
|
@ -4,7 +4,7 @@
|
|||
- add_page_specific_style 'page_bundles/pipeline_schedules'
|
||||
|
||||
%h3.page-title
|
||||
= _("Edit Pipeline Schedule %{id}") % { id: @schedule.id }
|
||||
= _("Edit Pipeline Schedule")
|
||||
%hr
|
||||
|
||||
= render "form"
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
- release = @releases.find { |release| release.tag == tag.name }
|
||||
- commit_status = @tag_pipeline_statuses[tag.name] unless @tag_pipeline_statuses.nil?
|
||||
|
||||
%li.flex-row.js-tag-list{ class: "gl-white-space-normal!" }
|
||||
%li.flex-row.js-tag-list{ class: "gl-white-space-normal! gl-align-items-flex-start!" }
|
||||
.row-main-content
|
||||
= sprite_icon('tag')
|
||||
= link_to tag.name, project_tag_path(@project, tag.name), class: 'item-title ref-name'
|
||||
|
@ -11,10 +11,6 @@
|
|||
%span.badge.badge-success.gl-ml-2.gl-badge.sm.badge-pill
|
||||
= s_('TagsPage|protected')
|
||||
|
||||
- if tag.message.present?
|
||||
|
||||
= strip_signature(tag.message)
|
||||
|
||||
- if commit
|
||||
.block-truncated
|
||||
= render 'projects/branches/commit', commit: commit, project: @project
|
||||
|
@ -28,6 +24,10 @@
|
|||
= _("Release")
|
||||
= link_to release.name, project_releases_path(@project, anchor: release.tag), class: 'gl-text-blue-600!'
|
||||
|
||||
- if tag.message.present?
|
||||
%pre.wrap
|
||||
= strip_signature(tag.message)
|
||||
|
||||
.row-fixed-content.controls.flex-row
|
||||
- if tag.has_signature?
|
||||
= render partial: 'projects/commit/signature', object: tag.signature
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
name: verify_participants_access
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/74906
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/347407
|
||||
milestone: '14.6'
|
||||
type: development
|
||||
group: group::source code
|
||||
default_enabled: false
|
|
@ -0,0 +1,29 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class EncryptStaticObjectsExternalStorageAuthToken < Gitlab::Database::Migration[1.0]
|
||||
class ApplicationSetting < ActiveRecord::Base
|
||||
self.table_name = 'application_settings'
|
||||
|
||||
scope :encrypted_token_is_null, -> { where(static_objects_external_storage_auth_token_encrypted: nil) }
|
||||
scope :encrypted_token_is_not_null, -> { where.not(static_objects_external_storage_auth_token_encrypted: nil) }
|
||||
scope :plaintext_token_is_not_null, -> { where.not(static_objects_external_storage_auth_token: nil) }
|
||||
end
|
||||
|
||||
def up
|
||||
ApplicationSetting.reset_column_information
|
||||
|
||||
ApplicationSetting.encrypted_token_is_null.plaintext_token_is_not_null.find_each do |application_setting|
|
||||
token_encrypted = Gitlab::CryptoHelper.aes256_gcm_encrypt(application_setting.static_objects_external_storage_auth_token)
|
||||
application_setting.update!(static_objects_external_storage_auth_token_encrypted: token_encrypted)
|
||||
end
|
||||
end
|
||||
|
||||
def down
|
||||
ApplicationSetting.reset_column_information
|
||||
|
||||
ApplicationSetting.encrypted_token_is_not_null.find_each do |application_setting|
|
||||
token = Gitlab::CryptoHelper.aes256_gcm_decrypt(application_setting.static_objects_external_storage_auth_token_encrypted)
|
||||
application_setting.update!(static_objects_external_storage_auth_token: token, static_objects_external_storage_auth_token_encrypted: nil)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1 @@
|
|||
2e6e432ecf7b2c885905fd4df6b57fa99b324f56cb0850d9fc792b4a9b363423
|
|
@ -472,7 +472,7 @@ module API
|
|||
end
|
||||
get ':id/issues/:issue_iid/participants' do
|
||||
issue = find_project_issue(params[:issue_iid])
|
||||
participants = ::Kaminari.paginate_array(issue.participants)
|
||||
participants = ::Kaminari.paginate_array(issue.visible_participants(current_user))
|
||||
|
||||
present paginate(participants), with: Entities::UserBasic, current_user: current_user, project: user_project
|
||||
end
|
||||
|
|
|
@ -282,7 +282,7 @@ module API
|
|||
get ':id/merge_requests/:merge_request_iid/participants', feature_category: :code_review, urgency: :low do
|
||||
merge_request = find_merge_request_with_access(params[:merge_request_iid])
|
||||
|
||||
participants = ::Kaminari.paginate_array(merge_request.participants)
|
||||
participants = ::Kaminari.paginate_array(merge_request.visible_participants(current_user))
|
||||
|
||||
present paginate(participants), with: Entities::UserBasic
|
||||
end
|
||||
|
|
|
@ -31,6 +31,10 @@ module Gitlab
|
|||
false
|
||||
end
|
||||
|
||||
def type
|
||||
nil
|
||||
end
|
||||
|
||||
def inspect
|
||||
"#<#{self.class.name}>"
|
||||
end
|
||||
|
|
|
@ -41,3 +41,7 @@ pages_deployments:
|
|||
- table: ci_builds
|
||||
column: ci_build_id
|
||||
on_delete: async_nullify
|
||||
terraform_state_versions:
|
||||
- table: ci_builds
|
||||
column: ci_build_id
|
||||
on_delete: async_nullify
|
||||
|
|
|
@ -9932,9 +9932,6 @@ msgstr ""
|
|||
msgid "Create new project"
|
||||
msgstr ""
|
||||
|
||||
msgid "Create new..."
|
||||
msgstr ""
|
||||
|
||||
msgid "Create or import your first project"
|
||||
msgstr ""
|
||||
|
||||
|
@ -12665,7 +12662,7 @@ msgstr ""
|
|||
msgid "Edit Password"
|
||||
msgstr ""
|
||||
|
||||
msgid "Edit Pipeline Schedule %{id}"
|
||||
msgid "Edit Pipeline Schedule"
|
||||
msgstr ""
|
||||
|
||||
msgid "Edit Release"
|
||||
|
@ -38792,12 +38789,21 @@ msgstr ""
|
|||
msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
|
||||
msgstr ""
|
||||
|
||||
msgid "VulnerabilityManagement|A removed or remediated vulnerability"
|
||||
msgstr ""
|
||||
|
||||
msgid "VulnerabilityManagement|A true-positive and will fix"
|
||||
msgstr ""
|
||||
|
||||
msgid "VulnerabilityManagement|A verified true-positive vulnerability"
|
||||
msgstr ""
|
||||
|
||||
msgid "VulnerabilityManagement|Add vulnerability finding"
|
||||
msgstr ""
|
||||
|
||||
msgid "VulnerabilityManagement|An unverified non-confirmed finding"
|
||||
msgstr ""
|
||||
|
||||
msgid "VulnerabilityManagement|Change status"
|
||||
msgstr ""
|
||||
|
||||
|
@ -38825,6 +38831,9 @@ msgstr ""
|
|||
msgid "VulnerabilityManagement|Requires assessment"
|
||||
msgstr ""
|
||||
|
||||
msgid "VulnerabilityManagement|Select a method"
|
||||
msgstr ""
|
||||
|
||||
msgid "VulnerabilityManagement|Something went wrong while trying to delete the comment. Please try again later."
|
||||
msgstr ""
|
||||
|
||||
|
@ -38894,9 +38903,18 @@ msgstr ""
|
|||
msgid "Vulnerability|Additional Info"
|
||||
msgstr ""
|
||||
|
||||
msgid "Vulnerability|Bug Bounty"
|
||||
msgstr ""
|
||||
|
||||
msgid "Vulnerability|CVSS v3"
|
||||
msgstr ""
|
||||
|
||||
msgid "Vulnerability|Class"
|
||||
msgstr ""
|
||||
|
||||
msgid "Vulnerability|Code Review"
|
||||
msgstr ""
|
||||
|
||||
msgid "Vulnerability|Comments"
|
||||
msgstr ""
|
||||
|
||||
|
@ -38912,21 +38930,33 @@ msgstr ""
|
|||
msgid "Vulnerability|Description"
|
||||
msgstr ""
|
||||
|
||||
msgid "Vulnerability|Details"
|
||||
msgstr ""
|
||||
|
||||
msgid "Vulnerability|Detected"
|
||||
msgstr ""
|
||||
|
||||
msgid "Vulnerability|Detection method"
|
||||
msgstr ""
|
||||
|
||||
msgid "Vulnerability|Download"
|
||||
msgstr ""
|
||||
|
||||
msgid "Vulnerability|Evidence"
|
||||
msgstr ""
|
||||
|
||||
msgid "Vulnerability|External Security Report"
|
||||
msgstr ""
|
||||
|
||||
msgid "Vulnerability|False positive detected"
|
||||
msgstr ""
|
||||
|
||||
msgid "Vulnerability|File"
|
||||
msgstr ""
|
||||
|
||||
msgid "Vulnerability|GitLab Security Report"
|
||||
msgstr ""
|
||||
|
||||
msgid "Vulnerability|Identifier"
|
||||
msgstr ""
|
||||
|
||||
|
@ -38936,6 +38966,9 @@ msgstr ""
|
|||
msgid "Vulnerability|Image"
|
||||
msgstr ""
|
||||
|
||||
msgid "Vulnerability|Information related how the vulnerability was discovered and its impact to the system."
|
||||
msgstr ""
|
||||
|
||||
msgid "Vulnerability|Links"
|
||||
msgstr ""
|
||||
|
||||
|
@ -38960,6 +38993,15 @@ msgstr ""
|
|||
msgid "Vulnerability|Scanner Provider"
|
||||
msgstr ""
|
||||
|
||||
msgid "Vulnerability|Security Audit"
|
||||
msgstr ""
|
||||
|
||||
msgid "Vulnerability|Select a severity"
|
||||
msgstr ""
|
||||
|
||||
msgid "Vulnerability|Set the status of the vulnerability finding based on the information available to you."
|
||||
msgstr ""
|
||||
|
||||
msgid "Vulnerability|Severity"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -45,10 +45,6 @@ module QA
|
|||
element :tree_holder, '.tree-holder' # rubocop:disable QA/ElementWithPattern
|
||||
end
|
||||
|
||||
view 'app/views/projects/buttons/_dropdown.html.haml' do
|
||||
element :create_new_dropdown
|
||||
end
|
||||
|
||||
view 'app/views/projects/buttons/_fork.html.haml' do
|
||||
element :fork_label, "%span= s_('ProjectOverview|Fork')" # rubocop:disable QA/ElementWithPattern
|
||||
element :fork_link, "link_to new_project_fork_path(@project)" # rubocop:disable QA/ElementWithPattern
|
||||
|
|
|
@ -81,7 +81,6 @@ RSpec.describe 'Database schema' do
|
|||
subscriptions: %w[user_id subscribable_id],
|
||||
suggestions: %w[commit_id],
|
||||
taggings: %w[tag_id taggable_id tagger_id],
|
||||
terraform_state_versions: %w[ci_build_id],
|
||||
timelogs: %w[user_id],
|
||||
todos: %w[target_id commit_id],
|
||||
uploads: %w[model_id],
|
||||
|
|
|
@ -445,6 +445,24 @@ RSpec.describe 'Admin updates settings' do
|
|||
|
||||
expect(current_settings.repository_storages_weighted).to eq('default' => 50)
|
||||
end
|
||||
|
||||
context 'External storage for repository static objects' do
|
||||
it 'changes Repository external storage settings' do
|
||||
encrypted_token = Gitlab::CryptoHelper.aes256_gcm_encrypt('OldToken')
|
||||
current_settings.update_attribute :static_objects_external_storage_auth_token_encrypted, encrypted_token
|
||||
|
||||
visit repository_admin_application_settings_path
|
||||
|
||||
page.within('.as-repository-static-objects') do
|
||||
fill_in 'application_setting_static_objects_external_storage_url', with: 'http://example.com'
|
||||
fill_in 'application_setting_static_objects_external_storage_auth_token', with: 'Token'
|
||||
click_button 'Save changes'
|
||||
end
|
||||
|
||||
expect(current_settings.static_objects_external_storage_url).to eq('http://example.com')
|
||||
expect(current_settings.static_objects_external_storage_auth_token).to eq('Token')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'Reporting page' do
|
||||
|
|
|
@ -21,7 +21,8 @@ RSpec.describe 'Project > Tags', :js do
|
|||
|
||||
context 'page with tags list' do
|
||||
it 'shows tag name' do
|
||||
expect(page).to have_content 'v1.1.0 Version 1.1.0'
|
||||
expect(page).to have_content 'v1.1.0'
|
||||
expect(page).to have_content 'Version 1.1.0'
|
||||
end
|
||||
|
||||
it 'shows tag edit button' do
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Resolvers::Users::ParticipantsResolver do
|
||||
include GraphqlHelpers
|
||||
|
||||
describe '#resolve' do
|
||||
let_it_be(:user) { create(:user) }
|
||||
let_it_be(:guest) { create(:user) }
|
||||
let_it_be(:project) { create(:project, :public) }
|
||||
let_it_be(:issue) { create(:issue, project: project) }
|
||||
let_it_be(:note) do
|
||||
create(
|
||||
:note,
|
||||
:confidential,
|
||||
project: project,
|
||||
noteable: issue,
|
||||
author: create(:user)
|
||||
)
|
||||
end
|
||||
|
||||
subject(:resolved_items) { resolve(described_class, args: {}, ctx: { current_user: current_user }, obj: issue)&.items }
|
||||
|
||||
before do
|
||||
project.add_guest(guest)
|
||||
project.add_developer(user)
|
||||
end
|
||||
|
||||
context 'when current user is not set' do
|
||||
let(:current_user) { nil }
|
||||
|
||||
it 'returns only publicly visible participants for this user' do
|
||||
is_expected.to match_array([issue.author])
|
||||
end
|
||||
end
|
||||
|
||||
context 'when current user does not have enough permissions' do
|
||||
let(:current_user) { guest }
|
||||
|
||||
it 'returns only publicly visible participants for this user' do
|
||||
is_expected.to match_array([issue.author])
|
||||
end
|
||||
end
|
||||
|
||||
context 'when current user has access to confidential notes' do
|
||||
let(:current_user) { user }
|
||||
|
||||
it 'returns all participants for this user' do
|
||||
is_expected.to match_array([issue.author, note.author])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -40,4 +40,10 @@ RSpec.describe Gitlab::Config::Entry::Undefined do
|
|||
expect(entry.specified?).to eq false
|
||||
end
|
||||
end
|
||||
|
||||
describe '#type' do
|
||||
it 'returns nil' do
|
||||
expect(entry.type).to eq nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
require_migration!
|
||||
|
||||
RSpec.describe EncryptStaticObjectsExternalStorageAuthToken, :migration do
|
||||
let(:application_settings) do
|
||||
Class.new(ActiveRecord::Base) do
|
||||
self.table_name = 'application_settings'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when static_objects_external_storage_auth_token is not set' do
|
||||
it 'does nothing' do
|
||||
application_settings.create!
|
||||
|
||||
reversible_migration do |migration|
|
||||
migration.before -> {
|
||||
settings = application_settings.first
|
||||
|
||||
expect(settings.static_objects_external_storage_auth_token).to be_nil
|
||||
expect(settings.static_objects_external_storage_auth_token_encrypted).to be_nil
|
||||
}
|
||||
|
||||
migration.after -> {
|
||||
settings = application_settings.first
|
||||
|
||||
expect(settings.static_objects_external_storage_auth_token).to be_nil
|
||||
expect(settings.static_objects_external_storage_auth_token_encrypted).to be_nil
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when static_objects_external_storage_auth_token is set' do
|
||||
it 'encrypts static_objects_external_storage_auth_token' do
|
||||
settings = application_settings.create!
|
||||
settings.update_column(:static_objects_external_storage_auth_token, 'Test')
|
||||
|
||||
reversible_migration do |migration|
|
||||
migration.before -> {
|
||||
settings = application_settings.first
|
||||
|
||||
expect(settings.static_objects_external_storage_auth_token).to eq('Test')
|
||||
expect(settings.static_objects_external_storage_auth_token_encrypted).to be_nil
|
||||
}
|
||||
migration.after -> {
|
||||
settings = application_settings.first
|
||||
|
||||
expect(settings.static_objects_external_storage_auth_token).to eq('Test')
|
||||
expect(settings.static_objects_external_storage_auth_token_encrypted).to be_present
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1239,4 +1239,30 @@ RSpec.describe ApplicationSetting do
|
|||
expect(subject.kroki_formats_excalidraw).to eq(true)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#static_objects_external_storage_auth_token=' do
|
||||
subject { setting.static_objects_external_storage_auth_token = token }
|
||||
|
||||
let(:token) { 'Test' }
|
||||
|
||||
it 'stores an encrypted version of the token' do
|
||||
subject
|
||||
|
||||
expect(setting[:static_objects_external_storage_auth_token]).to be_nil
|
||||
expect(setting[:static_objects_external_storage_auth_token_encrypted]).to be_present
|
||||
expect(setting.static_objects_external_storage_auth_token).to eq('Test')
|
||||
end
|
||||
|
||||
context 'when token is empty' do
|
||||
let(:token) { '' }
|
||||
|
||||
it 'removes an encrypted version of the token' do
|
||||
subject
|
||||
|
||||
expect(setting[:static_objects_external_storage_auth_token]).to be_nil
|
||||
expect(setting[:static_objects_external_storage_auth_token_encrypted]).to be_nil
|
||||
expect(setting.static_objects_external_storage_auth_token).to be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -29,7 +29,7 @@ RSpec.describe Ci::Build do
|
|||
it { is_expected.to have_one(:deployment) }
|
||||
it { is_expected.to have_one(:runner_session) }
|
||||
it { is_expected.to have_one(:trace_metadata) }
|
||||
it { is_expected.to have_many(:terraform_state_versions).dependent(:nullify).inverse_of(:build) }
|
||||
it { is_expected.to have_many(:terraform_state_versions).inverse_of(:build) }
|
||||
|
||||
it { is_expected.to validate_presence_of(:ref) }
|
||||
|
||||
|
|
|
@ -51,7 +51,9 @@ RSpec.describe Participable do
|
|||
end
|
||||
|
||||
it 'supports attributes returning another Participable' do
|
||||
other_model = Class.new { include Participable }
|
||||
other_model = Class.new do
|
||||
include Participable
|
||||
end
|
||||
|
||||
other_model.participant(:bar)
|
||||
model.participant(:foo)
|
||||
|
@ -115,6 +117,76 @@ RSpec.describe Participable do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#visible_participants' do
|
||||
before do
|
||||
allow(Ability).to receive(:allowed?).and_call_original
|
||||
allow(Ability).to receive(:allowed?).with(anything, :read_class, anything) { readable }
|
||||
end
|
||||
|
||||
let(:readable) { true }
|
||||
|
||||
it 'returns the list of participants' do
|
||||
model.participant(:foo)
|
||||
model.participant(:bar)
|
||||
|
||||
user1 = build(:user)
|
||||
user2 = build(:user)
|
||||
user3 = build(:user)
|
||||
project = build(:project, :public)
|
||||
instance = model.new
|
||||
|
||||
allow(instance).to receive_message_chain(:model_name, :element) { 'class' }
|
||||
expect(instance).to receive(:foo).and_return(user2)
|
||||
expect(instance).to receive(:bar).and_return(user3)
|
||||
expect(instance).to receive(:project).thrice.and_return(project)
|
||||
|
||||
participants = instance.visible_participants(user1)
|
||||
|
||||
expect(participants).to include(user2)
|
||||
expect(participants).to include(user3)
|
||||
end
|
||||
|
||||
context 'when Participable is not readable by the user' do
|
||||
let(:readable) { false }
|
||||
|
||||
it 'does not return unavailable participants' do
|
||||
model.participant(:bar)
|
||||
|
||||
instance = model.new
|
||||
user1 = build(:user)
|
||||
user2 = build(:user)
|
||||
project = build(:project, :public)
|
||||
|
||||
allow(instance).to receive_message_chain(:model_name, :element) { 'class' }
|
||||
allow(instance).to receive(:bar).and_return(user2)
|
||||
expect(instance).to receive(:project).thrice.and_return(project)
|
||||
|
||||
expect(instance.visible_participants(user1)).to be_empty
|
||||
end
|
||||
|
||||
context 'when feature flag is disabled' do
|
||||
before do
|
||||
stub_feature_flags(verify_participants_access: false)
|
||||
end
|
||||
|
||||
it 'returns unavailable participants' do
|
||||
model.participant(:bar)
|
||||
|
||||
instance = model.new
|
||||
user1 = build(:user)
|
||||
user2 = build(:user)
|
||||
project = build(:project, :public)
|
||||
|
||||
allow(instance).to receive_message_chain(:model_name, :element) { 'class' }
|
||||
allow(instance).to receive(:bar).and_return(user2)
|
||||
expect(instance).to receive(:project).thrice.and_return(project)
|
||||
|
||||
expect(instance.visible_participants(user1)).to match_array([user2])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#participant?' do
|
||||
let(:instance) { model.new }
|
||||
|
||||
|
|
|
@ -873,7 +873,7 @@ RSpec.describe API::Issues do
|
|||
end
|
||||
|
||||
it 'returns 404 if the issue is confidential' do
|
||||
post api("/projects/#{project.id}/issues/#{confidential_issue.iid}/participants", non_member)
|
||||
get api("/projects/#{project.id}/issues/#{confidential_issue.iid}/participants", non_member)
|
||||
|
||||
expect(response).to have_gitlab_http_status(:not_found)
|
||||
end
|
||||
|
|
|
@ -23,6 +23,20 @@ RSpec.describe Ci::ParseDotenvArtifactService do
|
|||
hash_including('key' => 'KEY2', 'value' => 'VAR2'))
|
||||
end
|
||||
|
||||
context 'when dotenv variables are conflicting against manual variables' do
|
||||
before do
|
||||
create(:ci_job_variable, job: build, key: 'KEY1')
|
||||
end
|
||||
|
||||
it 'returns an error message that there is a duplicate variable' do
|
||||
subject
|
||||
|
||||
expect(subject[:status]).to eq(:error)
|
||||
expect(subject[:message]).to include("Key (key, job_id)=(KEY1, #{build.id}) already exists.")
|
||||
expect(subject[:http_status]).to eq(:bad_request)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when parse error happens' do
|
||||
before do
|
||||
allow(service).to receive(:scan_line!) { raise described_class::ParserError, 'Invalid Format' }
|
||||
|
|
|
@ -28,4 +28,34 @@ RSpec.shared_examples 'issuable participants endpoint' do
|
|||
|
||||
expect(response).to have_gitlab_http_status(:not_found)
|
||||
end
|
||||
|
||||
context 'with a confidential note' do
|
||||
let!(:note) do
|
||||
create(
|
||||
:note,
|
||||
:confidential,
|
||||
project: project,
|
||||
noteable: entity,
|
||||
author: create(:user)
|
||||
)
|
||||
end
|
||||
|
||||
it 'returns a full list of participants' do
|
||||
get api("/projects/#{project.id}/#{area}/#{entity.iid}/participants", user)
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
participant_ids = json_response.map { |el| el['id'] }
|
||||
expect(participant_ids).to match_array([entity.author_id, note.author_id])
|
||||
end
|
||||
|
||||
context 'when user cannot see a confidential note' do
|
||||
it 'returns a limited list of participants' do
|
||||
get api("/projects/#{project.id}/#{area}/#{entity.iid}/participants", create(:user))
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
participant_ids = json_response.map { |el| el['id'] }
|
||||
expect(participant_ids).to match_array([entity.author_id])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,42 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'projects/buttons/_dropdown' do
|
||||
let(:user) { create(:user) }
|
||||
|
||||
context 'user with all abilities' do
|
||||
before do
|
||||
assign(:project, project)
|
||||
|
||||
allow(view).to receive(:current_user).and_return(user)
|
||||
allow(view).to receive(:can?).with(user, :push_code, project).and_return(true)
|
||||
allow(view).to receive(:can_collaborate_with_project?).and_return(true)
|
||||
end
|
||||
|
||||
context 'empty repository' do
|
||||
let(:project) { create(:project, :empty_repo) }
|
||||
|
||||
it 'has a link to create a new file' do
|
||||
render
|
||||
|
||||
expect(view).to render_template('projects/buttons/_dropdown')
|
||||
expect(rendered).to have_link('New file')
|
||||
end
|
||||
|
||||
it 'does not have a link to create a new branch' do
|
||||
render
|
||||
|
||||
expect(view).to render_template('projects/buttons/_dropdown')
|
||||
expect(rendered).not_to have_link('New branch')
|
||||
end
|
||||
|
||||
it 'does not have a link to create a new tag' do
|
||||
render
|
||||
|
||||
expect(view).to render_template('projects/buttons/_dropdown')
|
||||
expect(rendered).not_to have_link('New tag')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue