Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2021-08-31 21:10:43 +00:00
parent 34d6e7c91b
commit d9115c7779
73 changed files with 737 additions and 322 deletions

View File

@ -2,6 +2,20 @@
documentation](doc/development/changelog.md) for instructions on adding your own
entry.
## 14.2.2 (2021-08-31)
### Security (9 changes)
- [Prevent non-admins from configuring Jira connect app](gitlab-org/security/gitlab@1bc56361c9daa90accea65836d5a424168a2c544) ([merge request](gitlab-org/security/gitlab!1697))
- [Only create jira connect NS subscriptions for admins](gitlab-org/security/gitlab@c160da2cb32a5774fef149155cfd397981bf9173) ([merge request](gitlab-org/security/gitlab!1698))
- [Update apollo_upload_server dependency](gitlab-org/security/gitlab@5ef659b8c9a5a7338830171c62943d3b8bb16410) ([merge request](gitlab-org/security/gitlab!1699))
- [Ensure shared group members lose project access after group deletion](gitlab-org/security/gitlab@c94e934234a90f82e7fe291ed0f1d6a763b9a977) ([merge request](gitlab-org/security/gitlab!1683))
- [Update Import/Export to use public email when mapping users](gitlab-org/security/gitlab@13fb902c55c2dfe7ec2bf35f58a9cb3d93905d9a) ([merge request](gitlab-org/security/gitlab!1669)) **GitLab Enterprise Edition**
- [Require sign in for .keys endpoint on non-public instances](gitlab-org/security/gitlab@0979dd458e8fa0d4f5e184ef0b9ea042d79f6c14) ([merge request](gitlab-org/security/gitlab!1676))
- [Inherit user external status while creating project bots](gitlab-org/security/gitlab@93062909ffc093cb8f718a3ea3f2976292a9b9af) ([merge request](gitlab-org/security/gitlab!1675))
- [Escape issue reference and title for Jira issues](gitlab-org/security/gitlab@d25ef8599ec03ee80ef1bff7067b2269836400cf) ([merge request](gitlab-org/security/gitlab!1673)) **GitLab Enterprise Edition**
- [Fix stored XSS vulnerability in Datadog settings form](gitlab-org/security/gitlab@23b98dac7864992898992a153950247ac6ccb933) ([merge request](gitlab-org/security/gitlab!1670))
## 14.2.1 (2021-08-23)
### Fixed (1 change)
@ -563,6 +577,19 @@ entry.
- [Add helpful text to URL group validation and limit text](gitlab-org/gitlab@59a5a6266cb0d5434596170ffa36e4e74b8d2c2c) ([merge request](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/65369)) **GitLab Enterprise Edition**
- [Refactor external storage admin area configuration UI and docs](gitlab-org/gitlab@497ba4fc8f4ec1d234c9f5f1ec5c69712b8c7cb3) ([merge request](gitlab-org/gitlab!66219))
## 14.1.4 (2021-08-31)
### Security (8 changes)
- [Update apollo_upload_server dependency](gitlab-org/security/gitlab@34e7e3b7590fd76d0f618091551651e8065edfd2) ([merge request](gitlab-org/security/gitlab!1700))
- [Ensure shared group members lose project access after group deletion](gitlab-org/security/gitlab@4a7b8203776b719c06186c1b189a8cf21572fcd4) ([merge request](gitlab-org/security/gitlab!1684))
- [Fix stored XSS vulnerability in Datadog settings form](gitlab-org/security/gitlab@0906814af604e7fcab54a96bccadcba11207387d) ([merge request](gitlab-org/security/gitlab!1671))
- [Inherit user external status while creating project bots](gitlab-org/security/gitlab@d5a26c4145d917b5b49e207e03669d2b7e4ee617) ([merge request](gitlab-org/security/gitlab!1665))
- [Escape issue reference and title for Jira issues](gitlab-org/security/gitlab@4153444b76421ddf3a7fd21f1fc0500700a4e263) ([merge request](gitlab-org/security/gitlab!1662)) **GitLab Enterprise Edition**
- [Require sign in for .keys endpoint on non-public instances](gitlab-org/security/gitlab@b090b3f6dee6d21d93595c5e46e6c5c7fc30f1fb) ([merge request](gitlab-org/security/gitlab!1658))
- [Only create jira connect NS subscriptions for admins](gitlab-org/security/gitlab@3f2040c0e2c90f3fcafdbf0f86bd2591bd458dff) ([merge request](gitlab-org/security/gitlab!1648))
- [Prevent non-admins from configuring Jira connect app](gitlab-org/security/gitlab@fa864c0a2eaf450033f4c594cea07d9f24144cd6) ([merge request](gitlab-org/security/gitlab!1644))
## 14.1.3 (2021-08-17)
### Fixed (2 changes)
@ -1181,6 +1208,20 @@ entry.
- [Remove diffs gradual load feature flag](gitlab-org/gitlab@027d7c4327b5b6205a84281239027273517bf81b) ([merge request](gitlab-org/gitlab!55478))
- [Remove partial index for Hashed Storage migration](gitlab-org/gitlab@3ed017a1023d7b0941a7606b69e6caee8d22f15c) ([merge request](gitlab-org/gitlab!62920))
## 14.0.9 (2021-08-31)
### Security (9 changes)
- [Update apollo_upload_server dependency](gitlab-org/security/gitlab@ced741d93fa664f0c152f524949258bf969b7667) ([merge request](gitlab-org/security/gitlab!1701))
- [Ensure shared group members lose project access after group deletion](gitlab-org/security/gitlab@3a41f4e29c01188aaaf01ab5e3deec2a9eeed18e) ([merge request](gitlab-org/security/gitlab!1685))
- [Fix stored XSS vulnerability in Datadog settings form](gitlab-org/security/gitlab@269e5bf96b5e97c3b8e6f6b8b3f593d958de2ecb) ([merge request](gitlab-org/security/gitlab!1672))
- [Inherit user external status while creating project bots](gitlab-org/security/gitlab@5bae4e53bd4c363270b2fc2e308b81d2a2a388a6) ([merge request](gitlab-org/security/gitlab!1666))
- [Escape issue reference and title for Jira issues](gitlab-org/security/gitlab@0397f2b393d563559c49c39c0ba1d192d08a10d7) ([merge request](gitlab-org/security/gitlab!1663)) **GitLab Enterprise Edition**
- [Require sign in for .keys endpoint on non-public instances](gitlab-org/security/gitlab@13a7f6001f663b3745159fa37b518ba4a43355bd) ([merge request](gitlab-org/security/gitlab!1659))
- [Update Import/Export to use public email when mapping users](gitlab-org/security/gitlab@f3d1b800af55986cef83aeaf4df1312e3070f0c5) ([merge request](gitlab-org/security/gitlab!1654)) **GitLab Enterprise Edition**
- [Only create jira connect NS subscriptions for admins](gitlab-org/security/gitlab@34bdcd45f24eaa051702834fb6c3568e45721004) ([merge request](gitlab-org/security/gitlab!1647))
- [Prevent non-admins from configuring Jira connect app](gitlab-org/security/gitlab@4af692246224b1cd1e2fe3c6d0ac2613c0f8fe39) ([merge request](gitlab-org/security/gitlab!1643))
## 14.0.8 (2021-08-25)
### Fixed (1 change)

View File

@ -101,7 +101,7 @@ gem 'graphql', '~> 1.11.8'
# TODO: remove app/views/graphiql/rails/editors/show.html.erb when https://github.com/rmosolgo/graphiql-rails/pull/71 is released:
# https://gitlab.com/gitlab-org/gitlab/issues/31747
gem 'graphiql-rails', '~> 1.4.10'
gem 'apollo_upload_server', '~> 2.0.2'
gem 'apollo_upload_server', '~> 2.1.0'
gem 'graphql-docs', '~> 1.6.0', group: [:development, :test]
gem 'graphlient', '~> 0.4.0' # Used by BulkImport feature (group::import)

View File

@ -80,9 +80,9 @@ GEM
aes_key_wrap (1.1.0)
akismet (3.0.0)
android_key_attestation (0.3.0)
apollo_upload_server (2.0.2)
apollo_upload_server (2.1.0)
actionpack (>= 4.2)
graphql (>= 1.8)
rails (>= 4.2)
asana (0.10.3)
faraday (~> 1.0)
faraday_middleware (~> 1.0)
@ -1391,7 +1391,7 @@ DEPENDENCIES
acts-as-taggable-on (~> 7.0)
addressable (~> 2.8)
akismet (~> 3.0)
apollo_upload_server (~> 2.0.2)
apollo_upload_server (~> 2.1.0)
asana (~> 0.10.3)
asciidoctor (~> 2.0.10)
asciidoctor-include-ext (~> 0.3.1)

View File

@ -39,7 +39,7 @@ export default {
return this.value.map((i) => i.type);
},
tokens() {
const tokens = [
return [
{
type: this.$options.userType,
icon: 'user',
@ -77,20 +77,15 @@ export default {
token: PipelineStatusToken,
operators: OPERATOR_IS_ONLY,
},
];
if (gon.features.pipelineSourceFilter) {
tokens.push({
{
type: this.$options.sourceType,
icon: 'trigger-source',
title: s__('Pipeline|Source'),
unique: true,
token: PipelineSourceToken,
operators: OPERATOR_IS_ONLY,
});
}
return tokens;
},
];
},
parsedParams() {
return map(this.params, (val, key) => ({

View File

@ -47,7 +47,13 @@ class JiraConnect::AppDescriptorController < JiraConnect::ApplicationController
postInstallPage: {
key: 'gitlab-configuration',
name: { value: 'GitLab Configuration' },
url: relative_to_base_path(jira_connect_subscriptions_path)
url: relative_to_base_path(jira_connect_subscriptions_path),
conditions: [
{
condition: 'user_is_admin',
invert: false
}
]
}
}

View File

@ -38,12 +38,30 @@ class JiraConnect::ApplicationController < ApplicationController
end
def installation_from_jwt
return unless auth_token
strong_memoize(:installation_from_jwt) do
next unless claims['iss']
JiraConnectInstallation.find_by_client_key(claims['iss'])
end
end
def claims
strong_memoize(:claims) do
next {} unless auth_token
# Decode without verification to get `client_key` in `iss`
payload, _ = Atlassian::Jwt.decode(auth_token, nil, false)
JiraConnectInstallation.find_by_client_key(payload['iss'])
payload
end
end
def jira_user
strong_memoize(:jira_user) do
next unless installation_from_jwt
next unless claims['sub']
# This only works for Jira Cloud installations.
installation_from_jwt.client.user_info(claims['sub'])
end
end

View File

@ -44,7 +44,9 @@ class JiraConnect::SubscriptionsController < JiraConnect::ApplicationController
def destroy
subscription = current_jira_installation.subscriptions.find(params[:id])
if subscription.destroy
if !jira_user&.site_admin?
render json: { error: 'forbidden' }, status: :forbidden
elsif subscription.destroy
render json: { success: true }
else
render json: { error: subscription.errors.full_messages.join(', ') }, status: :unprocessable_entity
@ -54,7 +56,7 @@ class JiraConnect::SubscriptionsController < JiraConnect::ApplicationController
private
def create_service
JiraConnectSubscriptions::CreateService.new(current_jira_installation, current_user, namespace_path: params['namespace_path'])
JiraConnectSubscriptions::CreateService.new(current_jira_installation, current_user, namespace_path: params['namespace_path'], jira_user: jira_user)
end
def allow_rendering_in_iframe

View File

@ -14,10 +14,6 @@ class Projects::PipelinesController < Projects::ApplicationController
before_action :authorize_update_pipeline!, only: [:retry, :cancel]
before_action :ensure_pipeline, only: [:show, :downloadable_artifacts]
before_action do
push_frontend_feature_flag(:pipeline_source_filter, project, type: :development, default_enabled: :yaml)
end
# Will be removed with https://gitlab.com/gitlab-org/gitlab/-/issues/225596
before_action :redirect_for_legacy_scope_filter, only: [:index], if: -> { request.format.html? }
@ -297,10 +293,7 @@ class Projects::PipelinesController < Projects::ApplicationController
end
def index_params
permitted_params = [:scope, :username, :ref, :status]
permitted_params << :source if Feature.enabled?(:pipeline_source_filter, project, default_enabled: :yaml)
params.permit(*permitted_params)
params.permit(:scope, :username, :ref, :status, :source)
end
def enable_code_quality_walkthrough_experiment

View File

@ -20,7 +20,7 @@ class UsersController < ApplicationController
skip_before_action :authenticate_user!
prepend_before_action(only: [:show]) { authenticate_sessionless_user!(:rss) }
before_action :user, except: [:exists, :ssh_keys]
before_action :user, except: [:exists]
before_action :authorize_read_user_profile!,
only: [:calendar, :calendar_activities, :groups, :projects, :contributed, :starred, :snippets, :followers, :following]
@ -44,12 +44,7 @@ class UsersController < ApplicationController
# Get all keys of a user(params[:username]) in a text format
# Helpful for sysadmins to put in respective servers
#
# Uses `UserFinder` rather than `find_routable!` because this endpoint should
# be publicly available regardless of instance visibility settings.
def ssh_keys
user = UserFinder.new(params[:username]).find_by_username
render plain: user.all_ssh_keys.join("\n")
end

View File

@ -29,8 +29,7 @@ module Ci
items = by_username(items)
items = by_yaml_errors(items)
items = by_updated_at(items)
items = by_source(items) if Feature.enabled?(:pipeline_source_filter, project, default_enabled: :yaml)
items = by_source(items)
sort_items(items)
end

View File

@ -137,7 +137,7 @@ module IntegrationsHelper
def jira_issue_breadcrumb_link(issue_reference)
link_to '', { class: 'gl-display-flex gl-align-items-center gl-white-space-nowrap' } do
icon = image_tag image_path('illustrations/logos/jira.svg'), width: 15, height: 15, class: 'gl-mr-2'
[icon, issue_reference].join.html_safe
[icon, html_escape(issue_reference)].join.html_safe
end
end

View File

@ -169,7 +169,7 @@ module DesignManagement
@link_reference_pattern ||= begin
path_segment = %r{issues/#{Gitlab::Regex.issue}/designs}
ext = Regexp.new(Regexp.union(SAFE_IMAGE_EXT + DANGEROUS_IMAGE_EXT).source, Regexp::IGNORECASE)
valid_char = %r{[^/\s]} # any char that is not a forward slash or whitespace
valid_char = %r{[[:word:]\.\-\+]}
filename_pattern = %r{
(?<url_filename> #{valid_char}+ \. #{ext})
}x

View File

@ -8,7 +8,6 @@ module Integrations
DEFAULT_DOMAIN = 'datadoghq.com'
URL_TEMPLATE = 'https://webhooks-http-intake.logs.%{datadog_domain}/api/v2/webhook'
URL_TEMPLATE_API_KEYS = 'https://app.%{datadog_domain}/account/settings#api'
URL_API_KEYS_DOCS = "https://docs.#{DEFAULT_DOMAIN}/account_management/api-app-keys/"
SUPPORTED_EVENTS = %w[
@ -90,7 +89,7 @@ module Integrations
help: ERB::Util.html_escape(
s_('DatadogIntegration|%{linkOpen}API key%{linkClose} used for authentication with Datadog.')
) % {
linkOpen: '<a href="%s" target="_blank" rel="noopener noreferrer">'.html_safe % api_keys_url,
linkOpen: %Q{<a href="#{URL_API_KEYS_DOCS}" target="_blank" rel="noopener noreferrer">}.html_safe,
linkClose: '</a>'.html_safe
},
required: true
@ -132,12 +131,6 @@ module Integrations
url.to_s
end
def api_keys_url
return URL_API_KEYS_DOCS unless datadog_site.presence
sprintf(URL_TEMPLATE_API_KEYS, datadog_domain: datadog_domain)
end
def execute(data)
object_kind = data[:object_kind]
object_kind = 'job' if object_kind == 'build'

View File

@ -20,4 +20,8 @@ class JiraConnectInstallation < ApplicationRecord
id: JiraConnectSubscription.for_project(project)
})
}
def client
Atlassian::JiraConnect::Client.new(base_url, shared_secret)
end
end

View File

@ -29,14 +29,7 @@ module Groups
group.chat_team&.remove_mattermost_team(current_user)
# If any other groups are shared with the group that is being destroyed,
# we should specifically trigger update of all project authorizations
# for users that are the direct members of this group.
# If not, the project authorization records of these users to projects within the shared groups
# will never be removed, causing inconsistencies with access permissions.
if any_other_groups_are_shared_with_this_group?
user_ids_for_project_authorizations_refresh = group.users_ids_of_direct_members
end
user_ids_for_project_authorizations_refresh = obtain_user_ids_for_project_authorizations_refresh
group.destroy
@ -52,9 +45,33 @@ module Groups
private
def any_other_groups_are_shared_with_this_group?
def any_groups_shared_with_this_group?
group.shared_group_links.any?
end
def any_projects_shared_with_this_group?
group.project_group_links.any?
end
# Destroying a group automatically destroys all project authorizations directly
# associated with the group and descendents. However, project authorizations
# for projects and groups this group is shared with are not. Without a manual
# refresh, the project authorization records of these users to shared projects
# and projects within the shared groups will never be removed, causing
# inconsistencies with access permissions.
#
# This method retrieves the user IDs that need to be refreshed. If only
# groups are shared with this group, only direct members need to be refreshed.
# If projects are also shared with the group, direct members *and* shared
# members of other groups need to be refreshed.
# `Group#user_ids_for_project_authorizations` returns both direct and shared
# members' user IDs.
def obtain_user_ids_for_project_authorizations_refresh
return unless any_projects_shared_with_this_group? || any_groups_shared_with_this_group?
return group.user_ids_for_project_authorizations if any_projects_shared_with_this_group?
group.users_ids_of_direct_members
end
end
end

View File

@ -5,8 +5,11 @@ module JiraConnectSubscriptions
include Gitlab::Utils::StrongMemoize
MERGE_REQUEST_SYNC_BATCH_SIZE = 20
MERGE_REQUEST_SYNC_BATCH_DELAY = 1.minute.freeze
NOT_SITE_ADMIN = 'The Jira user is not a site administrator.'
def execute
return error(NOT_SITE_ADMIN, 403) unless can_administer_jira?
unless namespace && can?(current_user, :create_jira_connect_subscription, namespace)
return error('Invalid namespace. Please make sure you have sufficient permissions', 401)
end
@ -16,6 +19,10 @@ module JiraConnectSubscriptions
private
def can_administer_jira?
@params[:jira_user]&.site_admin?
end
def create_subscription
subscription = JiraConnectSubscription.new(installation: jira_connect_installation, namespace: namespace)

View File

@ -16,6 +16,8 @@ module ResourceAccessTokens
return error(user.errors.full_messages.to_sentence) unless user.persisted?
user.update!(external: true) if current_user.external?
access_level = params[:access_level] || Gitlab::Access::MAINTAINER
member = create_membership(resource, user, access_level)

View File

@ -1,8 +0,0 @@
---
name: pipeline_source_filter
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/67846
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/338347
milestone: '14.2'
type: development
group: group::pipeline execution
default_enabled: false

View File

@ -1146,14 +1146,22 @@ production: &base
# # Use multipart uploads when file size reaches 100MB, see
# # http://docs.aws.amazon.com/AmazonS3/latest/dev/uploadobjusingmpu.html
# multipart_chunk_size: 104857600
# # Turns on AWS Server-Side Encryption with Amazon S3-Managed Keys for backups, this is optional
# # encryption: 'AES256'
# # Turns on AWS Server-Side Encryption with Amazon Customer-Provided Encryption Keys for backups, this is optional
# # This should be set to the 256-bit encryption key for Amazon S3 to use to encrypt or decrypt your data.
# # 'encryption' must also be set in order for this to have any effect.
# # encryption_key: '<key>'
# # Specifies Amazon S3 storage class to use for backups, this is optional
# # Specifies Amazon S3 storage class to use for backups (optional)
# # storage_class: 'STANDARD'
# # Turns on AWS Server-Side Encryption with Amazon Customer-Provided Encryption Keys for backups, this is optional
# # 'encryption' must be set in order for this to have any effect.
# # 'encryption_key' should be set to the 256-bit encryption key for Amazon S3 to use to encrypt or decrypt your data.
# # encryption: 'AES256'
# # encryption_key: '<key>'
# #
# # Turns on AWS Server-Side Encryption with Amazon S3-Managed keys (optional)
# # https://docs.aws.amazon.com/AmazonS3/latest/userguide/serv-side-encryption.html
# # For SSE-S3, set 'server_side_encryption' to 'AES256'.
# # For SS3-KMS, set 'server_side_encryption' to 'aws:kms'. Set
# # 'server_side_encryption_kms_key_id' to the ARN of customer master key.
# # storage_options:
# # server_side_encryption: 'aws:kms'
# # server_side_encryption_kms_key_id: 'arn:aws:kms:YOUR-KEY-ID-HERE'
## Pseudonymizer exporter
pseudonymizer:

View File

@ -0,0 +1,5 @@
# frozen_string_literal: true
require 'apollo_upload_server'
ApolloUploadServer::Middleware.strict_mode = true

View File

@ -0,0 +1,33 @@
# frozen_string_literal: true
class UpdateExternalProjectBots < ActiveRecord::Migration[6.1]
include Gitlab::Database::MigrationHelpers
class User < ActiveRecord::Base
self.table_name = 'users'
end
disable_ddl_transaction!
TMP_INDEX_NAME = 'tmp_idx_update_external_project_bots'
def up
add_concurrent_index('users', 'id', name: TMP_INDEX_NAME, where: 'external = true')
ids = ActiveRecord::Base.connection
.execute("SELECT u.id FROM users u JOIN users u2 on u2.id = u.created_by_id WHERE u.user_type = 6 AND u2.external = true")
.map { |result| result['id'] }
ids.each_slice(10) do |group|
UpdateExternalProjectBots::User.where(id: group).update_all(external: true)
end
remove_concurrent_index_by_name('users', TMP_INDEX_NAME)
end
def down
remove_concurrent_index_by_name('users', TMP_INDEX_NAME) if index_exists_by_name?('users', TMP_INDEX_NAME)
# This migration is irreversible
end
end

View File

@ -0,0 +1 @@
f6f5e081672fb42adde980fa12f696f5d8fd11921ee52c1472b3d745bb11a5ff

View File

@ -32,6 +32,7 @@ GET /projects/:id/pipelines
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) owned by the authenticated user |
| `scope` | string | no | The scope of pipelines, one of: `running`, `pending`, `finished`, `branches`, `tags` |
| `status` | string | no | The status of pipelines, one of: `created`, `waiting_for_resource`, `preparing`, `pending`, `running`, `success`, `failed`, `canceled`, `skipped`, `manual`, `scheduled` |
| `source` | string | no | In [GitLab 14.3 and later](https://gitlab.com/gitlab-org/gitlab/-/issues/325439), how the pipeline was triggered, one of: `push`, `web`, `trigger`, `schedule`, `api`, `external`, `pipeline`, `chat`, `webide`, `merge_request_event`, `external_pull_request_event`, `parent_pipeline`, `ondemand_dast_scan`, or `ondemand_dast_validation`. |
| `ref` | string | no | The ref of pipelines |
| `sha` | string | no | The SHA of pipelines |
| `yaml_errors`| boolean | no | Returns pipelines with invalid configurations |
@ -55,6 +56,7 @@ Example of response
"iid": 12,
"project_id": 1,
"status": "pending",
"soure": "push",
"ref": "new-pipeline",
"sha": "a91957a858320c0e17f3a0eca7cfacbff50ea29a",
"web_url": "https://example.com/foo/bar/pipelines/47",
@ -66,6 +68,7 @@ Example of response
"iid": 13,
"project_id": 1,
"status": "pending",
"soure": "web",
"ref": "new-pipeline",
"sha": "eb94b618fb5865b26e80fdd8ae531b7a63ad851a",
"web_url": "https://example.com/foo/bar/pipelines/48",

View File

@ -122,6 +122,7 @@ you can filter the pipeline list by:
- Branch name
- Status ([GitLab 13.1 and later](https://gitlab.com/gitlab-org/gitlab/-/issues/217617))
- Tag ([GitLab 13.1 and later](https://gitlab.com/gitlab-org/gitlab/-/issues/217617))
- Source ([GitLab 14.3 and later](https://gitlab.com/gitlab-org/gitlab/-/issues/338347))
[Starting in GitLab 14.2](https://gitlab.com/gitlab-org/gitlab/-/issues/26621), you can change the
pipeline column to display the pipeline ID or the pipeline IID.

View File

@ -259,7 +259,7 @@ Only include the following attributes for the models specified:
included_attributes:
user:
- :id
- :email
- :public_email
# ...
```

View File

@ -6,6 +6,10 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# GitLab.com for Jira Cloud app **(FREE)**
NOTE:
Only Jira users with administrator level access are able to install or configure
the GitLab app for Jira Cloud.
## GitLab.com for Jira Cloud app **(FREE SAAS)**
You can integrate GitLab.com and Jira Cloud using the
@ -39,7 +43,8 @@ For a walkthrough of the integration with GitLab.com for Jira Cloud app, watch
![Sign in to GitLab.com in GitLab.com for Jira Cloud app](img/jira_dev_panel_setup_com_3_v13_9.png)
1. Select **Add namespace** to open the list of available namespaces.
1. Identify the namespace you want to link, and select **Link**.
1. Identify the namespace you want to link, and select **Link**. Only Jira site
administrators are permitted to add or remove namespaces for an installation.
![Link namespace in GitLab.com for Jira Cloud app](img/jira_dev_panel_setup_com_4_v13_9.png)

View File

@ -44,7 +44,7 @@ Note the following:
- Group members are exported as project members, as long as the user has
a maintainer or administrator role in the group where the exported project lives.
- Project members with the [Owner role](../../permissions.md) are imported as Maintainers.
- Imported users can be mapped by their primary email on self-managed instances, if an administrative user (not an owner) does the import.
- Imported users can be mapped by their public email on self-managed instances, if an administrative user (not an owner) does the import.
Additionally, the user must be an existing member of the namespace, or the user can be added as a
member of the project for contributions to be mapped.
Otherwise, a supplementary comment is left to mention that the original author and

View File

@ -4,11 +4,9 @@ module API
module Entities
module Ci
class PipelineBasic < Grape::Entity
expose :id, :project_id, :sha, :ref, :status
expose :id, :project_id, :sha, :ref, :status, :source
expose :created_at, :updated_at
expose :source, if: ->(pipeline, options) { ::Feature.enabled?(:pipeline_source_filter, options[:project], default_enabled: :yaml) }
expose :web_url do |pipeline, _options|
Gitlab::Routing.url_helpers.project_pipeline_url(pipeline.project, pipeline)
end

View File

@ -30,8 +30,21 @@ module Atlassian
responses.compact
end
def user_info(account_id)
r = get('/rest/api/3/user', { accountId: account_id, expand: 'groups' })
JiraUser.new(r.parsed_response) if r.code == 200
end
private
def get(path, query_params)
uri = URI.join(@base_uri, path)
uri.query = URI.encode_www_form(query_params)
self.class.get(uri, headers: headers(uri, 'GET'))
end
def store_ff_info(project:, feature_flags:, **opts)
items = feature_flags.map { |flag| ::Atlassian::JiraConnect::Serializers::FeatureFlagEntity.represent(flag, opts) }
items.reject! { |item| item.issue_keys.empty? }
@ -99,10 +112,11 @@ module Atlassian
self.class.post(uri, headers: headers(uri), body: metadata.merge(payload).to_json)
end
def headers(uri)
def headers(uri, http_method = 'POST')
{
'Authorization' => "JWT #{jwt_token('POST', uri)}",
'Content-Type' => 'application/json'
'Authorization' => "JWT #{jwt_token(http_method, uri)}",
'Content-Type' => 'application/json',
'Accept' => 'application/json'
}
end

View File

@ -0,0 +1,18 @@
# frozen_string_literal: true
module Atlassian
module JiraConnect
class JiraUser
def initialize(data)
@data = data
end
def site_admin?
groups = @data.dig('groups', 'items')
return false unless groups
groups.any? { |g| g['name'] == 'site-admins' }
end
end
end
end

View File

@ -47,10 +47,12 @@ module Backup
return
end
directory = connect_to_remote_directory(Gitlab.config.backup.upload)
directory = connect_to_remote_directory
upload = directory.files.create(create_attributes)
if directory.files.create(create_attributes)
if upload
progress.puts "done".color(:green)
upload
else
puts "uploading backup to #{remote_directory} failed".color(:red)
raise Backup::Error, 'Backup failed'
@ -206,11 +208,16 @@ module Backup
@backup_file_list.map {|item| item.gsub("#{FILE_NAME_SUFFIX}", "")}
end
def connect_to_remote_directory(options)
config = ObjectStorage::Config.new(options)
config.load_provider
def object_storage_config
@object_storage_config ||= begin
config = ObjectStorage::Config.new(Gitlab.config.backup.upload)
config.load_provider
config
end
end
connection = ::Fog::Storage.new(config.credentials)
def connect_to_remote_directory
connection = ::Fog::Storage.new(object_storage_config.credentials)
# We only attempt to create the directory for local backups. For AWS
# and other cloud providers, we cannot guarantee the user will have
@ -280,10 +287,8 @@ module Backup
key: remote_target,
body: File.open(File.join(backup_path, tar_file)),
multipart_chunk_size: Gitlab.config.backup.upload.multipart_chunk_size,
encryption: Gitlab.config.backup.upload.encryption,
encryption_key: Gitlab.config.backup.upload.encryption_key,
storage_class: Gitlab.config.backup.upload.storage_class
}
}.merge(encryption_attributes)
# Google bucket-only policies prevent setting an ACL. In any case, by default,
# all objects are set to the default ACL, which is project-private:
@ -293,6 +298,19 @@ module Backup
attrs
end
def encryption_attributes
return object_storage_config.fog_attributes if object_storage_config.aws_server_side_encryption_enabled?
# Use customer-managed keys. Also, this preserves
# backward-compatibility for existing usages of `SSE-S3` that
# don't set `backup.upload.storage_options.server_side_encryption`
# to `'AES256'`.
{
encryption_key: Gitlab.config.backup.upload.encryption_key,
encryption: Gitlab.config.backup.upload.encryption
}
end
def google_provider?
Gitlab.config.backup.upload.connection&.provider&.downcase == 'google'
end

View File

@ -20,7 +20,7 @@ tree:
included_attributes:
user:
- :id
- :email
- :public_email
- :username
author:
- :name

View File

@ -20,7 +20,7 @@ tree:
included_attributes:
user:
- :id
- :email
- :public_email
- :username
author:
- :name

View File

@ -19,7 +19,8 @@ module Gitlab
@exported_members.inject(missing_keys_tracking_hash) do |hash, member|
if member['user']
old_user_id = member['user']['id']
existing_user = User.find_by(find_user_query(member))
old_user_email = member.dig('user', 'public_email') || member.dig('user', 'email')
existing_user = User.find_by(find_user_query(old_user_email)) if old_user_email
hash[old_user_id] = existing_user.id if existing_user && add_team_member(member, existing_user)
else
add_team_member(member)
@ -94,8 +95,8 @@ module Gitlab
relation_class: relation_class)
end
def find_user_query(member)
user_arel[:email].eq(member['user']['email'])
def find_user_query(email)
user_arel[:email].eq(email)
end
def user_arel

View File

@ -115,7 +115,7 @@ tree:
included_attributes:
user:
- :id
- :email
- :public_email
- :username
author:
- :name

View File

@ -11,7 +11,7 @@ module Gitlab
# this if the change to the renderer output is a new feature or a
# minor bug fix.
# See: https://gitlab.com/gitlab-org/gitlab/-/issues/330313
CACHE_COMMONMARK_VERSION = 28
CACHE_COMMONMARK_VERSION = 29
CACHE_COMMONMARK_VERSION_START = 10
BaseError = Class.new(StandardError)

View File

@ -176,7 +176,7 @@ module Gitlab
::Gitlab::Middleware::Multipart::Handler.new(env, message).with_open_files do
@app.call(env)
end
rescue UploadedFile::InvalidPathError => e
rescue UploadedFile::InvalidPathError, ApolloUploadServer::GraphQLDataBuilder::OutOfBounds => e
[400, { 'Content-Type' => 'text/plain' }, [e.message]]
end
end

View File

@ -84,13 +84,16 @@ module ObjectStorage
def fog_attributes
@fog_attributes ||= begin
return {} unless enabled? && aws?
return {} unless server_side_encryption.present?
return {} unless aws_server_side_encryption_enabled?
aws_server_side_encryption_headers.compact
end
end
def aws_server_side_encryption_enabled?
aws? && server_side_encryption.present?
end
private
# This returns a Hash of HTTP encryption headers to send along to S3.

View File

@ -54,7 +54,10 @@ RSpec.describe JiraConnect::AppDescriptorController do
postInstallPage: {
key: 'gitlab-configuration',
name: { value: 'GitLab Configuration' },
url: '/subscriptions'
url: '/subscriptions',
conditions: contain_exactly(
a_hash_including(condition: 'user_is_admin', invert: false)
)
},
jiraDevelopmentTool: {
actions: {

View File

@ -102,11 +102,17 @@ RSpec.describe JiraConnect::SubscriptionsController do
end
context 'with valid JWT' do
let(:jwt) { Atlassian::Jwt.encode({ iss: installation.client_key }, installation.shared_secret) }
let(:claims) { { iss: installation.client_key, sub: 1234 } }
let(:jwt) { Atlassian::Jwt.encode(claims, installation.shared_secret) }
let(:jira_user) { { 'groups' => { 'items' => [{ 'name' => jira_group_name }] } } }
let(:jira_group_name) { 'site-admins' }
context 'signed in to GitLab' do
before do
sign_in(user)
WebMock
.stub_request(:get, "#{installation.base_url}/rest/api/3/user?accountId=1234&expand=groups")
.to_return(body: jira_user.to_json, status: 200, headers: { 'Content-Type' => 'application/json' })
end
context 'dev panel integration is available' do
@ -120,6 +126,16 @@ RSpec.describe JiraConnect::SubscriptionsController do
expect(response).to have_gitlab_http_status(:ok)
end
end
context 'when the Jira user is not a site-admin' do
let(:jira_group_name) { 'some-other-group' }
it 'returns forbidden' do
subject
expect(response).to have_gitlab_http_status(:forbidden)
end
end
end
context 'not signed in to GitLab' do
@ -134,8 +150,14 @@ RSpec.describe JiraConnect::SubscriptionsController do
describe '#destroy' do
let(:subscription) { create(:jira_connect_subscription, installation: installation) }
let(:jira_user) { { 'groups' => { 'items' => [{ 'name' => jira_group_name }] } } }
let(:jira_group_name) { 'site-admins' }
before do
WebMock
.stub_request(:get, "#{installation.base_url}/rest/api/3/user?accountId=1234&expand=groups")
.to_return(body: jira_user.to_json, status: 200, headers: { 'Content-Type' => 'application/json' })
delete :destroy, params: { jwt: jwt, id: subscription.id }
end
@ -148,12 +170,23 @@ RSpec.describe JiraConnect::SubscriptionsController do
end
context 'with valid JWT' do
let(:jwt) { Atlassian::Jwt.encode({ iss: installation.client_key }, installation.shared_secret) }
let(:claims) { { iss: installation.client_key, sub: 1234 } }
let(:jwt) { Atlassian::Jwt.encode(claims, installation.shared_secret) }
it 'deletes the subscription' do
expect { subscription.reload }.to raise_error ActiveRecord::RecordNotFound
expect(response).to have_gitlab_http_status(:ok)
end
context 'when the Jira user is not a site admin' do
let(:jira_group_name) { 'some-other-group' }
it 'does not delete the subscription' do
expect(response).to have_gitlab_http_status(:forbidden)
expect { subscription.reload }.not_to raise_error
end
end
end
end
end

View File

@ -19,8 +19,18 @@ RSpec.describe 'Upload a design through graphQL', :js do
let_it_be(:user) { create(:user, :admin) }
let_it_be(:personal_access_token) { create(:personal_access_token, user: user) }
let_it_be(:design) { create(:design) }
let_it_be(:operations) { { "operationName": "uploadDesign", "variables": { "files": [], "projectPath": design.project.full_path, "iid": design.issue.iid }, "query": query }.to_json }
let_it_be(:map) { { "1": ["variables.files.0"] }.to_json }
let_it_be(:operations) do
{
"operationName": "uploadDesign",
"variables": {
"files": [nil],
"projectPath": design.project.full_path,
"iid": design.issue.iid
},
"query": query
}.to_json
end
let(:url) { capybara_url("/api/graphql?private_token=#{personal_access_token.token}") }
let(:file) { fixture_file_upload('spec/fixtures/dk.png') }

View File

@ -258,20 +258,8 @@ RSpec.describe Ci::PipelinesFinder do
let!(:push_pipeline) { create(:ci_pipeline, project: project, source: 'push') }
let!(:api_pipeline) { create(:ci_pipeline, project: project, source: 'api') }
context 'when `pipeline_source_filter` feature flag is disabled' do
before do
stub_feature_flags(pipeline_source_filter: false)
end
it 'returns all the pipelines' do
is_expected.to contain_exactly(web_pipeline, push_pipeline, api_pipeline)
end
end
context 'when `pipeline_source_filter` feature flag is enabled' do
it 'returns only the matched pipeline' do
is_expected.to eq([web_pipeline])
end
it 'returns only the matched pipeline' do
is_expected.to eq([web_pipeline])
end
end

File diff suppressed because one or more lines are too long

View File

@ -2398,7 +2398,7 @@
"requested_at": null,
"user": {
"id": 16,
"email": "bernard_willms@gitlabexample.com",
"public_email": "bernard_willms@gitlabexample.com",
"username": "bernard_willms"
}
},
@ -2418,7 +2418,7 @@
"requested_at": null,
"user": {
"id": 6,
"email": "saul_will@gitlabexample.com",
"public_email": "saul_will@gitlabexample.com",
"username": "saul_will"
}
},
@ -2438,7 +2438,7 @@
"requested_at": null,
"user": {
"id": 15,
"email": "breanna_sanford@wolf.com",
"public_email": "breanna_sanford@wolf.com",
"username": "emmet.schamberger"
}
},
@ -2458,7 +2458,7 @@
"requested_at": null,
"user": {
"id": 26,
"email": "user4@example.com",
"public_email": "user4@example.com",
"username": "user4"
}
}

View File

@ -1,4 +1,4 @@
{"id":36,"access_level":40,"source_id":5,"source_type":"Project","user_id":16,"notification_level":3,"created_at":"2016-06-14T15:02:03.834Z","updated_at":"2016-06-14T15:02:03.834Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"user":{"id":16,"email":"bernard_willms@gitlabexample.com","username":"bernard_willms"}}
{"id":35,"access_level":10,"source_id":5,"source_type":"Project","user_id":6,"notification_level":3,"created_at":"2016-06-14T15:02:03.811Z","updated_at":"2016-06-14T15:02:03.811Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"user":{"id":6,"email":"saul_will@gitlabexample.com","username":"saul_will"}}
{"id":34,"access_level":20,"source_id":5,"source_type":"Project","user_id":15,"notification_level":3,"created_at":"2016-06-14T15:02:03.776Z","updated_at":"2016-06-14T15:02:03.776Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"user":{"id":15,"email":"breanna_sanford@wolf.com","username":"emmet.schamberger"}}
{"id":33,"access_level":20,"source_id":5,"source_type":"Project","user_id":26,"notification_level":3,"created_at":"2016-06-14T15:02:03.742Z","updated_at":"2016-06-14T15:02:03.742Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"user":{"id":26,"email":"user4@example.com","username":"user4"}}
{"id":36,"access_level":40,"source_id":5,"source_type":"Project","user_id":16,"notification_level":3,"created_at":"2016-06-14T15:02:03.834Z","updated_at":"2016-06-14T15:02:03.834Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"user":{"id":16,"public_email":"bernard_willms@gitlabexample.com","username":"bernard_willms"}}
{"id":35,"access_level":10,"source_id":5,"source_type":"Project","user_id":6,"notification_level":3,"created_at":"2016-06-14T15:02:03.811Z","updated_at":"2016-06-14T15:02:03.811Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"user":{"id":6,"public_email":"saul_will@gitlabexample.com","username":"saul_will"}}
{"id":34,"access_level":20,"source_id":5,"source_type":"Project","user_id":15,"notification_level":3,"created_at":"2016-06-14T15:02:03.776Z","updated_at":"2016-06-14T15:02:03.776Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"user":{"id":15,"public_email":"breanna_sanford@wolf.com","username":"emmet.schamberger"}}
{"id":33,"access_level":20,"source_id":5,"source_type":"Project","user_id":26,"notification_level":3,"created_at":"2016-06-14T15:02:03.742Z","updated_at":"2016-06-14T15:02:03.742Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"user":{"id":26,"public_email":"user4@example.com","username":"user4"}}

View File

@ -425,7 +425,7 @@
"override":false,
"user":{
"id":1,
"email":"admin@example.com",
"public_email":"admin@example.com",
"username":"root"
}
},
@ -448,7 +448,7 @@
"override":false,
"user":{
"id":2,
"email":"user_2@gitlabexample.com",
"public_email":"user_2@gitlabexample.com",
"username":"user_2"
}
}

View File

@ -377,7 +377,7 @@
"override": false,
"user": {
"id": 42,
"email": "moriah@collinsmurphy.com",
"public_email": "moriah@collinsmurphy.com",
"username": "reported_user_15"
}
},
@ -400,7 +400,7 @@
"override": false,
"user": {
"id": 271,
"email": "garret@connellystark.ca",
"public_email": "garret@connellystark.ca",
"username": "charlesetta"
}
},
@ -423,7 +423,7 @@
"override": false,
"user": {
"id": 206,
"email": "gwendolyn_robel@gitlabexample.com",
"public_email": "gwendolyn_robel@gitlabexample.com",
"username": "gwendolyn_robel"
}
},
@ -446,7 +446,7 @@
"override": false,
"user": {
"id": 39,
"email": "alexis_berge@kerlukeklein.us",
"public_email": "alexis_berge@kerlukeklein.us",
"username": "reported_user_12"
}
},
@ -469,7 +469,7 @@
"override": false,
"user": {
"id": 1624,
"email": "adriene.mcclure@gitlabexample.com",
"public_email": "adriene.mcclure@gitlabexample.com",
"username": "adriene.mcclure"
}
},
@ -492,7 +492,7 @@
"override": false,
"user": {
"id": 1,
"email": "admin@example.com",
"public_email": "admin@example.com",
"username": "root"
}
}
@ -1338,7 +1338,7 @@
"override": false,
"user": {
"id": 1087,
"email": "paige@blanda.info",
"public_email": "paige@blanda.info",
"username": "billi_auer"
}
},
@ -1361,7 +1361,7 @@
"override": false,
"user": {
"id": 171,
"email": "heidi@bosco.co.uk",
"public_email": "heidi@bosco.co.uk",
"username": "gerard.cruickshank"
}
},
@ -1384,7 +1384,7 @@
"override": false,
"user": {
"id": 1157,
"email": "larisa.bruen@carroll.biz",
"public_email": "larisa.bruen@carroll.biz",
"username": "milagros.reynolds"
}
},
@ -1407,7 +1407,7 @@
"override": false,
"user": {
"id": 14,
"email": "madlyn_kovacek@wiza.ca",
"public_email": "madlyn_kovacek@wiza.ca",
"username": "monique.gusikowski"
}
},
@ -1430,7 +1430,7 @@
"override": false,
"user": {
"id": 1167,
"email": "mirella@koepp.ca",
"public_email": "mirella@koepp.ca",
"username": "eileen"
}
},
@ -1453,7 +1453,7 @@
"override": false,
"user": {
"id": 1,
"email": "admin@example.com",
"public_email": "admin@example.com",
"username": "root"
}
}
@ -1909,7 +1909,7 @@
"override": false,
"user": {
"id": 1533,
"email": "jose@cassin.ca",
"public_email": "jose@cassin.ca",
"username": "buster"
}
},
@ -1932,7 +1932,7 @@
"override": false,
"user": {
"id": 1586,
"email": "carie@gleichner.us",
"public_email": "carie@gleichner.us",
"username": "dominque"
}
},
@ -1955,7 +1955,7 @@
"override": false,
"user": {
"id": 190,
"email": "delois@funk.biz",
"public_email": "delois@funk.biz",
"username": "kittie"
}
},
@ -1978,7 +1978,7 @@
"override": false,
"user": {
"id": 254,
"email": "tyra.lowe@whitemckenzie.co.uk",
"public_email": "tyra.lowe@whitemckenzie.co.uk",
"username": "kassie"
}
},
@ -2001,7 +2001,7 @@
"override": false,
"user": {
"id": 503,
"email": "tyesha.brakus@bruen.ca",
"public_email": "tyesha.brakus@bruen.ca",
"username": "charise"
}
},
@ -2024,7 +2024,7 @@
"override": false,
"user": {
"id": 1,
"email": "admin@example.com",
"public_email": "admin@example.com",
"username": "root"
}
}

View File

@ -1,6 +1,6 @@
{"id":13766,"access_level":30,"source_id":4351,"source_type":"Namespace","user_id":42,"notification_level":3,"created_at":"2019-11-20T17:04:36.184Z","updated_at":"2019-11-20T17:04:36.184Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":42,"email":"moriah@collinsmurphy.com","username":"reported_user_15"}}
{"id":13765,"access_level":40,"source_id":4351,"source_type":"Namespace","user_id":271,"notification_level":3,"created_at":"2019-11-20T17:04:36.044Z","updated_at":"2019-11-20T17:04:36.044Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":271,"email":"garret@connellystark.ca","username":"charlesetta"}}
{"id":13764,"access_level":30,"source_id":4351,"source_type":"Namespace","user_id":206,"notification_level":3,"created_at":"2019-11-20T17:04:35.840Z","updated_at":"2019-11-20T17:04:35.840Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":206,"email":"gwendolyn_robel@gitlabexample.com","username":"gwendolyn_robel"}}
{"id":13763,"access_level":10,"source_id":4351,"source_type":"Namespace","user_id":39,"notification_level":3,"created_at":"2019-11-20T17:04:35.704Z","updated_at":"2019-11-20T17:04:35.704Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":39,"email":"alexis_berge@kerlukeklein.us","username":"reported_user_12"}}
{"id":13762,"access_level":20,"source_id":4351,"source_type":"Namespace","user_id":1624,"notification_level":3,"created_at":"2019-11-20T17:04:35.566Z","updated_at":"2019-11-20T17:04:35.566Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":1624,"email":"adriene.mcclure@gitlabexample.com","username":"adriene.mcclure"}}
{"id":12920,"access_level":50,"source_id":4351,"source_type":"Namespace","user_id":1,"notification_level":3,"created_at":"2019-11-20T17:01:53.505Z","updated_at":"2019-11-20T17:01:53.505Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":1,"email":"admin@example.com","username":"root"}}
{"id":13766,"access_level":30,"source_id":4351,"source_type":"Namespace","user_id":42,"notification_level":3,"created_at":"2019-11-20T17:04:36.184Z","updated_at":"2019-11-20T17:04:36.184Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":42,"public_email":"moriah@collinsmurphy.com","username":"reported_user_15"}}
{"id":13765,"access_level":40,"source_id":4351,"source_type":"Namespace","user_id":271,"notification_level":3,"created_at":"2019-11-20T17:04:36.044Z","updated_at":"2019-11-20T17:04:36.044Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":271,"public_email":"garret@connellystark.ca","username":"charlesetta"}}
{"id":13764,"access_level":30,"source_id":4351,"source_type":"Namespace","user_id":206,"notification_level":3,"created_at":"2019-11-20T17:04:35.840Z","updated_at":"2019-11-20T17:04:35.840Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":206,"public_email":"gwendolyn_robel@gitlabexample.com","username":"gwendolyn_robel"}}
{"id":13763,"access_level":10,"source_id":4351,"source_type":"Namespace","user_id":39,"notification_level":3,"created_at":"2019-11-20T17:04:35.704Z","updated_at":"2019-11-20T17:04:35.704Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":39,"public_email":"alexis_berge@kerlukeklein.us","username":"reported_user_12"}}
{"id":13762,"access_level":20,"source_id":4351,"source_type":"Namespace","user_id":1624,"notification_level":3,"created_at":"2019-11-20T17:04:35.566Z","updated_at":"2019-11-20T17:04:35.566Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":1624,"public_email":"adriene.mcclure@gitlabexample.com","username":"adriene.mcclure"}}
{"id":12920,"access_level":50,"source_id":4351,"source_type":"Namespace","user_id":1,"notification_level":3,"created_at":"2019-11-20T17:01:53.505Z","updated_at":"2019-11-20T17:01:53.505Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":1,"public_email":"admin@example.com","username":"root"}}

View File

@ -1,6 +1,6 @@
{"id":13771,"access_level":30,"source_id":4352,"source_type":"Namespace","user_id":1087,"notification_level":3,"created_at":"2019-11-20T17:04:36.968Z","updated_at":"2019-11-20T17:04:36.968Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":1087,"email":"paige@blanda.info","username":"billi_auer"}}
{"id":13770,"access_level":20,"source_id":4352,"source_type":"Namespace","user_id":171,"notification_level":3,"created_at":"2019-11-20T17:04:36.821Z","updated_at":"2019-11-20T17:04:36.821Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":171,"email":"heidi@bosco.co.uk","username":"gerard.cruickshank"}}
{"id":13769,"access_level":30,"source_id":4352,"source_type":"Namespace","user_id":1157,"notification_level":3,"created_at":"2019-11-20T17:04:36.606Z","updated_at":"2019-11-20T17:04:36.606Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":1157,"email":"larisa.bruen@carroll.biz","username":"milagros.reynolds"}}
{"id":13768,"access_level":40,"source_id":4352,"source_type":"Namespace","user_id":14,"notification_level":3,"created_at":"2019-11-20T17:04:36.465Z","updated_at":"2019-11-20T17:04:36.465Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":14,"email":"madlyn_kovacek@wiza.ca","username":"monique.gusikowski"}}
{"id":13767,"access_level":10,"source_id":4352,"source_type":"Namespace","user_id":1167,"notification_level":3,"created_at":"2019-11-20T17:04:36.324Z","updated_at":"2019-11-20T17:04:36.324Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":1167,"email":"mirella@koepp.ca","username":"eileen"}}
{"id":12921,"access_level":50,"source_id":4352,"source_type":"Namespace","user_id":1,"notification_level":3,"created_at":"2019-11-20T17:01:53.953Z","updated_at":"2019-11-20T17:01:53.953Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":1,"email":"admin@example.com","username":"root"}}
{"id":13771,"access_level":30,"source_id":4352,"source_type":"Namespace","user_id":1087,"notification_level":3,"created_at":"2019-11-20T17:04:36.968Z","updated_at":"2019-11-20T17:04:36.968Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":1087,"public_email":"paige@blanda.info","username":"billi_auer"}}
{"id":13770,"access_level":20,"source_id":4352,"source_type":"Namespace","user_id":171,"notification_level":3,"created_at":"2019-11-20T17:04:36.821Z","updated_at":"2019-11-20T17:04:36.821Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":171,"public_email":"heidi@bosco.co.uk","username":"gerard.cruickshank"}}
{"id":13769,"access_level":30,"source_id":4352,"source_type":"Namespace","user_id":1157,"notification_level":3,"created_at":"2019-11-20T17:04:36.606Z","updated_at":"2019-11-20T17:04:36.606Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":1157,"public_email":"larisa.bruen@carroll.biz","username":"milagros.reynolds"}}
{"id":13768,"access_level":40,"source_id":4352,"source_type":"Namespace","user_id":14,"notification_level":3,"created_at":"2019-11-20T17:04:36.465Z","updated_at":"2019-11-20T17:04:36.465Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":14,"public_email":"madlyn_kovacek@wiza.ca","username":"monique.gusikowski"}}
{"id":13767,"access_level":10,"source_id":4352,"source_type":"Namespace","user_id":1167,"notification_level":3,"created_at":"2019-11-20T17:04:36.324Z","updated_at":"2019-11-20T17:04:36.324Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":1167,"public_email":"mirella@koepp.ca","username":"eileen"}}
{"id":12921,"access_level":50,"source_id":4352,"source_type":"Namespace","user_id":1,"notification_level":3,"created_at":"2019-11-20T17:01:53.953Z","updated_at":"2019-11-20T17:01:53.953Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":1,"public_email":"admin@example.com","username":"root"}}

View File

@ -1,6 +1,6 @@
{"id":13786,"access_level":30,"source_id":4355,"source_type":"Namespace","user_id":1533,"notification_level":3,"created_at":"2019-11-20T17:04:39.405Z","updated_at":"2019-11-20T17:04:39.405Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":1533,"email":"jose@cassin.ca","username":"buster"}}
{"id":13785,"access_level":10,"source_id":4355,"source_type":"Namespace","user_id":1586,"notification_level":3,"created_at":"2019-11-20T17:04:39.269Z","updated_at":"2019-11-20T17:04:39.269Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":1586,"email":"carie@gleichner.us","username":"dominque"}}
{"id":13784,"access_level":30,"source_id":4355,"source_type":"Namespace","user_id":190,"notification_level":3,"created_at":"2019-11-20T17:04:39.127Z","updated_at":"2019-11-20T17:04:39.127Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":190,"email":"delois@funk.biz","username":"kittie"}}
{"id":13783,"access_level":20,"source_id":4355,"source_type":"Namespace","user_id":254,"notification_level":3,"created_at":"2019-11-20T17:04:38.971Z","updated_at":"2019-11-20T17:04:38.971Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":254,"email":"tyra.lowe@whitemckenzie.co.uk","username":"kassie"}}
{"id":13782,"access_level":40,"source_id":4355,"source_type":"Namespace","user_id":503,"notification_level":3,"created_at":"2019-11-20T17:04:38.743Z","updated_at":"2019-11-20T17:04:38.743Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":503,"email":"tyesha.brakus@bruen.ca","username":"charise"}}
{"id":12924,"access_level":50,"source_id":4355,"source_type":"Namespace","user_id":1,"notification_level":3,"created_at":"2019-11-20T17:01:54.145Z","updated_at":"2019-11-20T17:01:54.145Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":1,"email":"admin@example.com","username":"root"}}
{"id":13786,"access_level":30,"source_id":4355,"source_type":"Namespace","user_id":1533,"notification_level":3,"created_at":"2019-11-20T17:04:39.405Z","updated_at":"2019-11-20T17:04:39.405Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":1533,"public_email":"jose@cassin.ca","username":"buster"}}
{"id":13785,"access_level":10,"source_id":4355,"source_type":"Namespace","user_id":1586,"notification_level":3,"created_at":"2019-11-20T17:04:39.269Z","updated_at":"2019-11-20T17:04:39.269Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":1586,"public_email":"carie@gleichner.us","username":"dominque"}}
{"id":13784,"access_level":30,"source_id":4355,"source_type":"Namespace","user_id":190,"notification_level":3,"created_at":"2019-11-20T17:04:39.127Z","updated_at":"2019-11-20T17:04:39.127Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":190,"public_email":"delois@funk.biz","username":"kittie"}}
{"id":13783,"access_level":20,"source_id":4355,"source_type":"Namespace","user_id":254,"notification_level":3,"created_at":"2019-11-20T17:04:38.971Z","updated_at":"2019-11-20T17:04:38.971Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":254,"public_email":"tyra.lowe@whitemckenzie.co.uk","username":"kassie"}}
{"id":13782,"access_level":40,"source_id":4355,"source_type":"Namespace","user_id":503,"notification_level":3,"created_at":"2019-11-20T17:04:38.743Z","updated_at":"2019-11-20T17:04:38.743Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":503,"public_email":"tyesha.brakus@bruen.ca","username":"charise"}}
{"id":12924,"access_level":50,"source_id":4355,"source_type":"Namespace","user_id":1,"notification_level":3,"created_at":"2019-11-20T17:01:54.145Z","updated_at":"2019-11-20T17:01:54.145Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":1,"public_email":"admin@example.com","username":"root"}}

View File

@ -299,7 +299,7 @@
"override": false,
"user": {
"id": 42,
"email": "moriah@collinsmurphy.com",
"public_email": "moriah@collinsmurphy.com",
"username": "reported_user_15"
}
},
@ -322,7 +322,7 @@
"override": false,
"user": {
"id": 271,
"email": "garret@connellystark.ca",
"public_email": "garret@connellystark.ca",
"username": "charlesetta"
}
},
@ -345,7 +345,7 @@
"override": false,
"user": {
"id": 206,
"email": "margaret.bergnaum@reynolds.us",
"public_email": "margaret.bergnaum@reynolds.us",
"username": "gwendolyn_robel"
}
},
@ -368,7 +368,7 @@
"override": false,
"user": {
"id": 39,
"email": "alexis_berge@kerlukeklein.us",
"public_email": "alexis_berge@kerlukeklein.us",
"username": "reported_user_12"
}
},
@ -391,7 +391,7 @@
"override": false,
"user": {
"id": 1624,
"email": "nakesha.herzog@powlowski.com",
"public_email": "nakesha.herzog@powlowski.com",
"username": "adriene.mcclure"
}
},
@ -414,7 +414,7 @@
"override": false,
"user": {
"id": 1,
"email": "admin@example.com",
"public_email": "admin@example.com",
"username": "root"
}
}

View File

@ -1,6 +1,6 @@
{"id":13766,"access_level":30,"source_id":4351,"source_type":"Namespace","user_id":42,"notification_level":3,"created_at":"2019-11-20T17:04:36.184Z","updated_at":"2019-11-20T17:04:36.184Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":42,"email":"moriah@collinsmurphy.com","username":"reported_user_15"}}
{"id":13765,"access_level":40,"source_id":4351,"source_type":"Namespace","user_id":271,"notification_level":3,"created_at":"2019-11-20T17:04:36.044Z","updated_at":"2019-11-20T17:04:36.044Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":271,"email":"garret@connellystark.ca","username":"charlesetta"}}
{"id":13764,"access_level":30,"source_id":4351,"source_type":"Namespace","user_id":206,"notification_level":3,"created_at":"2019-11-20T17:04:35.840Z","updated_at":"2019-11-20T17:04:35.840Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":206,"email":"margaret.bergnaum@reynolds.us","username":"gwendolyn_robel"}}
{"id":13763,"access_level":10,"source_id":4351,"source_type":"Namespace","user_id":39,"notification_level":3,"created_at":"2019-11-20T17:04:35.704Z","updated_at":"2019-11-20T17:04:35.704Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":39,"email":"alexis_berge@kerlukeklein.us","username":"reported_user_12"}}
{"id":13762,"access_level":20,"source_id":4351,"source_type":"Namespace","user_id":1624,"notification_level":3,"created_at":"2019-11-20T17:04:35.566Z","updated_at":"2019-11-20T17:04:35.566Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":1624,"email":"nakesha.herzog@powlowski.com","username":"adriene.mcclure"}}
{"id":12920,"access_level":50,"source_id":4351,"source_type":"Namespace","user_id":1,"notification_level":3,"created_at":"2019-11-20T17:01:53.505Z","updated_at":"2019-11-20T17:01:53.505Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":1,"email":"admin@example.com","username":"root"}}
{"id":13766,"access_level":30,"source_id":4351,"source_type":"Namespace","user_id":42,"notification_level":3,"created_at":"2019-11-20T17:04:36.184Z","updated_at":"2019-11-20T17:04:36.184Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":42,"public_email":"moriah@collinsmurphy.com","username":"reported_user_15"}}
{"id":13765,"access_level":40,"source_id":4351,"source_type":"Namespace","user_id":271,"notification_level":3,"created_at":"2019-11-20T17:04:36.044Z","updated_at":"2019-11-20T17:04:36.044Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":271,"public_email":"garret@connellystark.ca","username":"charlesetta"}}
{"id":13764,"access_level":30,"source_id":4351,"source_type":"Namespace","user_id":206,"notification_level":3,"created_at":"2019-11-20T17:04:35.840Z","updated_at":"2019-11-20T17:04:35.840Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":206,"public_email":"margaret.bergnaum@reynolds.us","username":"gwendolyn_robel"}}
{"id":13763,"access_level":10,"source_id":4351,"source_type":"Namespace","user_id":39,"notification_level":3,"created_at":"2019-11-20T17:04:35.704Z","updated_at":"2019-11-20T17:04:35.704Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":39,"public_email":"alexis_berge@kerlukeklein.us","username":"reported_user_12"}}
{"id":13762,"access_level":20,"source_id":4351,"source_type":"Namespace","user_id":1624,"notification_level":3,"created_at":"2019-11-20T17:04:35.566Z","updated_at":"2019-11-20T17:04:35.566Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":1624,"public_email":"nakesha.herzog@powlowski.com","username":"adriene.mcclure"}}
{"id":12920,"access_level":50,"source_id":4351,"source_type":"Namespace","user_id":1,"notification_level":3,"created_at":"2019-11-20T17:01:53.505Z","updated_at":"2019-11-20T17:01:53.505Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":1,"public_email":"admin@example.com","username":"root"}}

View File

@ -33,8 +33,6 @@ describe('Pipelines filtered search', () => {
};
beforeEach(() => {
window.gon = { features: { pipelineSourceFilter: true } };
mock = new MockAdapter(axios);
jest.spyOn(Api, 'projectUsers').mockResolvedValue(users);

View File

@ -105,8 +105,6 @@ describe('Pipelines', () => {
});
beforeEach(() => {
window.gon = { features: { pipelineSourceFilter: true } };
mock = new MockAdapter(axios);
jest.spyOn(window.history, 'pushState');

View File

@ -98,4 +98,19 @@ RSpec.describe IntegrationsHelper do
end
end
end
describe '#jira_issue_breadcrumb_link' do
let(:issue_reference) { nil }
subject { helper.jira_issue_breadcrumb_link(issue_reference) }
context 'when issue_reference contains HTML' do
let(:issue_reference) { "<script>alert('XSS')</script>" }
it 'escapes issue reference' do
is_expected.not_to include(issue_reference)
is_expected.to include(html_escape(issue_reference))
end
end
end
end

View File

@ -432,6 +432,77 @@ RSpec.describe Backup::Manager do
end
end
context 'with AWS with server side encryption' do
let(:connection) { ::Fog::Storage.new(Gitlab.config.backup.upload.connection.symbolize_keys) }
let(:encryption_key) { nil }
let(:encryption) { nil }
let(:storage_options) { nil }
before do
stub_backup_setting(
upload: {
connection: {
provider: 'AWS',
aws_access_key_id: 'AWS_ACCESS_KEY_ID',
aws_secret_access_key: 'AWS_SECRET_ACCESS_KEY'
},
remote_directory: 'directory',
multipart_chunk_size: Gitlab.config.backup.upload.multipart_chunk_size,
encryption: encryption,
encryption_key: encryption_key,
storage_options: storage_options,
storage_class: nil
}
)
connection.directories.create(key: Gitlab.config.backup.upload.remote_directory)
end
context 'with SSE-S3 without using storage_options' do
let(:encryption) { 'AES256' }
it 'sets encryption attributes' do
result = subject.upload
expect(result.key).to be_present
expect(result.encryption).to eq('AES256')
expect(result.encryption_key).to be_nil
expect(result.kms_key_id).to be_nil
end
end
context 'with SSE-C (customer-provided keys) options' do
let(:encryption) { 'AES256' }
let(:encryption_key) { SecureRandom.hex }
it 'sets encryption attributes' do
result = subject.upload
expect(result.key).to be_present
expect(result.encryption).to eq(encryption)
expect(result.encryption_key).to eq(encryption_key)
expect(result.kms_key_id).to be_nil
end
end
context 'with SSE-KMS options' do
let(:storage_options) do
{
server_side_encryption: 'aws:kms',
server_side_encryption_kms_key_id: 'arn:aws:kms:12345'
}
end
it 'sets encryption attributes' do
result = subject.upload
expect(result.key).to be_present
expect(result.encryption).to eq('aws:kms')
expect(result.kms_key_id).to eq('arn:aws:kms:12345')
end
end
end
context 'with Google provider' do
before do
stub_backup_setting(

View File

@ -90,11 +90,8 @@ RSpec.describe Banzai::Filter::References::DesignReferenceFilter do
[
['simple.png'],
['SIMPLE.PNG'],
['has spaces.png'],
['has-hyphen.jpg'],
['snake_case.svg'],
['has "quotes".svg'],
['has <special> characters [o].svg']
['snake_case.svg']
]
end
@ -138,40 +135,25 @@ RSpec.describe Banzai::Filter::References::DesignReferenceFilter do
end
end
context 'a design with a quoted filename' do
let(:filename) { %q{A "very" good file.png} }
let(:design) { create(:design, :with_versions, issue: issue, filename: filename) }
it 'links to the design' do
expect(doc.css('a').first.attr('href'))
.to eq url_for_design(design)
end
end
context 'internal reference' do
it_behaves_like 'a reference containing an element node'
context 'the reference is valid' do
it_behaves_like 'a good link reference'
it_behaves_like 'a good link reference'
context 'the filename needs to be escaped' do
where(:filename) do
[
['with some spaces.png'],
['with <script>console.log("pwded")<%2Fscript>.png']
]
end
context 'the filename contains invalid characters' do
where(:filename) do
[
['with some spaces.png'],
['with <script>console.log("pwded")<%2Fscript>.png'],
['foo"bar.png'],
['A "very" good file.png']
]
end
with_them do
let(:design) { create(:design, :with_versions, filename: filename, issue: issue) }
let(:link) { doc.css('a').first }
with_them do
let(:design) { create(:design, :with_versions, filename: filename, issue: issue) }
it 'replaces the content with the reference, but keeps the link', :aggregate_failures do
expect(doc.text).to eq(CGI.unescapeHTML("Added #{design.to_reference}"))
expect(link.attr('title')).to eq(design.filename)
expect(link.attr('href')).to eq(design_url)
end
end
it_behaves_like 'a no-op filter'
end
end

View File

@ -102,7 +102,7 @@ RSpec.describe Gitlab::ImportExport::Base::RelationFactory do
"updated_at" => "2016-11-18T09:29:42.634Z",
"user" => {
"id" => 999,
"email" => new_user.email,
"public_email" => new_user.email,
"username" => new_user.username
}
}

View File

@ -83,11 +83,12 @@ RSpec.describe Gitlab::ImportExport::Group::LegacyTreeSaver do
let(:user2) { create(:user, email: 'group@member.com') }
let(:member_emails) do
saved_group_json['members'].map do |pm|
pm['user']['email']
pm['user']['public_email']
end
end
before do
user2.update(public_email: user2.email)
group.add_developer(user2)
end

View File

@ -24,7 +24,7 @@ RSpec.describe Gitlab::ImportExport::MembersMapper do
"user" =>
{
"id" => exported_user_id,
"email" => user2.email,
"public_email" => user2.email,
"username" => 'test'
},
"user_id" => 19
@ -122,7 +122,7 @@ RSpec.describe Gitlab::ImportExport::MembersMapper do
"user" =>
{
"id" => exported_user_id,
"email" => user2.email,
"public_email" => user2.email,
"username" => 'test'
},
"user_id" => 19
@ -157,6 +157,37 @@ RSpec.describe Gitlab::ImportExport::MembersMapper do
expect(members_mapper.map[exported_user_id]).to eq(user2.id)
end
end
context 'when user has email exported' do
let(:exported_members) do
[
{
"id" => 2,
"access_level" => 40,
"source_id" => 14,
"source_type" => source_type,
"notification_level" => 3,
"created_at" => "2016-03-11T10:21:44.822Z",
"updated_at" => "2016-03-11T10:21:44.822Z",
"created_by_id" => nil,
"invite_email" => nil,
"invite_token" => nil,
"invite_accepted_at" => nil,
"user" =>
{
"id" => exported_user_id,
"email" => user2.email,
"username" => 'test'
},
"user_id" => 19
}
]
end
it 'maps a member' do
expect(members_mapper.map[exported_user_id]).to eq(user2.id)
end
end
end
context 'when importable is Project' do
@ -212,7 +243,7 @@ RSpec.describe Gitlab::ImportExport::MembersMapper do
before do
group.add_users([user, user2], GroupMember::DEVELOPER)
user.update(email: 'invite@test.com')
user.update(public_email: 'invite@test.com')
end
it 'maps the importer' do

View File

@ -119,7 +119,7 @@ RSpec.describe Gitlab::ImportExport::Project::RelationFactory, :use_clean_rails_
"updated_at" => "2016-11-18T09:29:42.634Z",
"user" => {
"id" => admin.id,
"email" => admin.email,
"public_email" => admin.email,
"username" => admin.username
}
}
@ -187,7 +187,7 @@ RSpec.describe Gitlab::ImportExport::Project::RelationFactory, :use_clean_rails_
"updated_at" => "2016-11-18T09:29:42.634Z",
"user" => {
"id" => admin.id,
"email" => admin.email,
"public_email" => admin.email,
"username" => admin.username
}
}

View File

@ -299,12 +299,13 @@ RSpec.describe Gitlab::ImportExport::Project::TreeSaver do
let(:member_emails) do
emails = subject.map do |pm|
pm['user']['email']
pm['user']['public_email']
end
emails
end
before do
user2.update(public_email: user2.email)
group.add_developer(user2)
end

View File

@ -188,6 +188,7 @@ RSpec.describe ObjectStorage::Config do
end
context 'with SSE-KMS enabled' do
it { expect(subject.aws_server_side_encryption_enabled?).to be true }
it { expect(subject.server_side_encryption).to eq('AES256') }
it { expect(subject.server_side_encryption_kms_key_id).to eq('arn:aws:12345') }
it { expect(subject.fog_attributes.keys).to match_array(%w(x-amz-server-side-encryption x-amz-server-side-encryption-aws-kms-key-id)) }
@ -196,6 +197,7 @@ RSpec.describe ObjectStorage::Config do
context 'with only server side encryption enabled' do
let(:storage_options) { { server_side_encryption: 'AES256' } }
it { expect(subject.aws_server_side_encryption_enabled?).to be true }
it { expect(subject.server_side_encryption).to eq('AES256') }
it { expect(subject.server_side_encryption_kms_key_id).to be_nil }
it { expect(subject.fog_attributes).to eq({ 'x-amz-server-side-encryption' => 'AES256' }) }
@ -204,6 +206,7 @@ RSpec.describe ObjectStorage::Config do
context 'without encryption enabled' do
let(:storage_options) { {} }
it { expect(subject.aws_server_side_encryption_enabled?).to be false }
it { expect(subject.server_side_encryption).to be_nil }
it { expect(subject.server_side_encryption_kms_key_id).to be_nil }
it { expect(subject.fog_attributes).to eq({}) }
@ -215,6 +218,5 @@ RSpec.describe ObjectStorage::Config do
end
it { expect(subject.enabled?).to be false }
it { expect(subject.fog_attributes).to eq({}) }
end
end

View File

@ -0,0 +1,25 @@
# frozen_string_literal: true
require 'spec_helper'
require_migration!('update_external_project_bots')
RSpec.describe UpdateExternalProjectBots, :migration do
def create_user(**extra_options)
defaults = { projects_limit: 0, email: "#{extra_options[:username]}@example.com" }
table(:users).create!(defaults.merge(extra_options))
end
it 'sets bot users as external if were created by external users' do
internal_user = create_user(username: 'foo')
external_user = create_user(username: 'bar', external: true)
internal_project_bot = create_user(username: 'foo2', user_type: 6, created_by_id: internal_user.id, external: false)
external_project_bot = create_user(username: 'bar2', user_type: 6, created_by_id: external_user.id, external: false)
migrate!
expect(table(:users).find(internal_project_bot.id).external).to eq false
expect(table(:users).find(external_project_bot.id).external).to eq true
end
end

View File

@ -572,6 +572,12 @@ RSpec.describe DesignManagement::Design do
expect(described_class.link_reference_pattern).not_to match(url_for_designs(issue))
end
it 'intentionally ignores filenames with any special character' do
design = build(:design, issue: issue, filename: '"invalid')
expect(described_class.link_reference_pattern).not_to match(url_for_design(design))
end
where(:ext) do
(described_class::SAFE_IMAGE_EXT + described_class::DANGEROUS_IMAGE_EXT).flat_map do |ext|
[[ext], [ext.upcase]]
@ -593,14 +599,6 @@ RSpec.describe DesignManagement::Design do
)
end
context 'the file needs to be encoded' do
let(:filename) { "my file.#{ext}" }
it 'extracts the encoded filename' do
expect(captures).to include('url_filename' => 'my%20file.' + ext)
end
end
context 'the file is all upper case' do
let(:filename) { "file.#{ext}".upcase }

View File

@ -127,18 +127,6 @@ RSpec.describe Integrations::Datadog do
end
end
describe '#api_keys_url' do
subject { instance.api_keys_url }
it { is_expected.to eq("https://app.#{dd_site}/account/settings#api") }
context 'with unset datadog_site' do
let(:dd_site) { '' }
it { is_expected.to eq("https://docs.datadoghq.com/account_management/api-app-keys/") }
end
end
describe '#test' do
subject(:result) { saved_instance.test(pipeline_data) }

View File

@ -37,24 +37,10 @@ RSpec.describe API::Ci::Pipelines do
end
describe 'keys in the response' do
context 'when `pipeline_source_filter` feature flag is disabled' do
before do
stub_feature_flags(pipeline_source_filter: false)
end
it 'includes pipeline source' do
get api("/projects/#{project.id}/pipelines", user)
it 'does not includes pipeline source' do
get api("/projects/#{project.id}/pipelines", user)
expect(json_response.first.keys).to contain_exactly(*%w[id project_id sha ref status web_url created_at updated_at])
end
end
context 'when `pipeline_source_filter` feature flag is disabled' do
it 'includes pipeline source' do
get api("/projects/#{project.id}/pipelines", user)
expect(json_response.first.keys).to contain_exactly(*%w[id project_id sha ref status web_url created_at updated_at source])
end
expect(json_response.first.keys).to contain_exactly(*%w[id project_id sha ref status web_url created_at updated_at source])
end
end
@ -323,37 +309,20 @@ RSpec.describe API::Ci::Pipelines do
create(:ci_pipeline, project: project, source: :api)
end
context 'when `pipeline_source_filter` feature flag is disabled' do
before do
stub_feature_flags(pipeline_source_filter: false)
end
it 'returns matched pipelines' do
get api("/projects/#{project.id}/pipelines", user), params: { source: 'web' }
it 'returns all pipelines' do
get api("/projects/#{project.id}/pipelines", user), params: { source: 'web' }
expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers
expect(json_response).not_to be_empty
expect(json_response.length).to be >= 3
end
expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers
expect(json_response).not_to be_empty
json_response.each { |r| expect(r['source']).to eq('web') }
end
context 'when `pipeline_source_filter` feature flag is enabled' do
it 'returns matched pipelines' do
get api("/projects/#{project.id}/pipelines", user), params: { source: 'web' }
context 'when source is invalid' do
it 'returns bad_request' do
get api("/projects/#{project.id}/pipelines", user), params: { source: 'invalid-source' }
expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers
expect(json_response).not_to be_empty
json_response.each { |r| expect(r['source']).to eq('web') }
end
context 'when source is invalid' do
it 'returns bad_request' do
get api("/projects/#{project.id}/pipelines", user), params: { source: 'invalid-source' }
expect(response).to have_gitlab_http_status(:bad_request)
end
expect(response).to have_gitlab_http_status(:bad_request)
end
end
end

View File

@ -11,6 +11,7 @@ RSpec.describe "uploading designs" do
let(:project) { issue.project }
let(:files) { [fixture_file_upload("spec/fixtures/dk.png")] }
let(:variables) { {} }
let(:mutation_response) { graphql_mutation_response(:design_management_upload) }
def mutation
input = {
@ -21,14 +22,32 @@ RSpec.describe "uploading designs" do
graphql_mutation(:design_management_upload, input)
end
let(:mutation_response) { graphql_mutation_response(:design_management_upload) }
before do
enable_design_management
project.add_developer(current_user)
end
context 'when the input does not include a null value for each mapped file' do
let(:operations) { { query: mutation.query, variables: mutation.variables.merge(files: []) } }
let(:mapping) { { '1' => ['variables.files.0'] } }
let(:params) do
{ '1' => files.first, operations: operations.to_json, map: mapping.to_json }
end
it 'returns an error' do
workhorse_post_with_file(api('/', current_user, version: 'graphql'),
params: params,
file_key: '1'
)
expect(response).to have_attributes(
code: eq('400'),
body: include('out-of-bounds')
)
end
end
it "returns an error if the user is not allowed to upload designs" do
post_graphql_mutation_with_uploads(mutation, current_user: create(:user))

View File

@ -274,7 +274,11 @@ RSpec.describe UsersController do
stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC])
end
it_behaves_like 'renders all public keys'
it 'redirects to sign in' do
get "/#{user.username}.keys"
expect(response).to redirect_to(new_user_session_path)
end
end
end
end

View File

@ -152,56 +152,125 @@ RSpec.describe Groups::DestroyService do
end
context 'for shared groups within different hierarchies' do
let(:shared_with_group) { group }
let!(:shared_group) { create(:group, :private) }
let!(:shared_group_child) { create(:group, :private, parent: shared_group) }
let!(:shared_group_user) { create(:user) }
let(:group1) { create(:group, :private) }
let(:group2) { create(:group, :private) }
let!(:project) { create(:project, group: shared_group) }
let!(:project_child) { create(:project, group: shared_group_child) }
let(:group1_user) { create(:user) }
let(:group2_user) { create(:user) }
before do
shared_group.add_user(shared_group_user, Gitlab::Access::OWNER)
create(:group_group_link, shared_group: shared_group, shared_with_group: shared_with_group)
shared_with_group.refresh_members_authorized_projects
group1.add_user(group1_user, Gitlab::Access::OWNER)
group2.add_user(group2_user, Gitlab::Access::OWNER)
end
context 'the shared group is deleted' do
it 'updates project authorization' do
expect(shared_group_user.can?(:read_project, project)).to eq(true)
expect(shared_group_user.can?(:read_project, project_child)).to eq(true)
context 'when a project is shared with a group' do
let!(:group1_project) { create(:project, :private, group: group1) }
destroy_group(shared_group, shared_group_user, false)
expect(shared_group_user.can?(:read_project, project)).to eq(false)
expect(shared_group_user.can?(:read_project, project_child)).to eq(false)
before do
create(:project_group_link, project: group1_project, group: group2)
end
it 'does not make use of specific service to update project_authorizations records' do
expect(UserProjectAccessChangedService)
.not_to receive(:new).with(shared_group.user_ids_for_project_authorizations).and_call_original
context 'and the shared group is deleted' do
it 'updates project authorizations so group2 users no longer have access', :aggregate_failures do
expect(group1_user.can?(:read_project, group1_project)).to eq(true)
expect(group2_user.can?(:read_project, group1_project)).to eq(true)
destroy_group(shared_group, shared_group_user, false)
destroy_group(group2, group2_user, false)
expect(group1_user.can?(:read_project, group1_project)).to eq(true)
expect(group2_user.can?(:read_project, group1_project)).to eq(false)
end
it 'calls the service to update project authorizations only with necessary user ids' do
expect(UserProjectAccessChangedService)
.to receive(:new).with(array_including(group2_user.id)).and_call_original
destroy_group(group2, group2_user, false)
end
end
context 'and the group is shared with another group' do
let(:group3) { create(:group, :private) }
let(:group3_user) { create(:user) }
before do
group3.add_user(group3_user, Gitlab::Access::OWNER)
create(:group_group_link, shared_group: group2, shared_with_group: group3)
group3.refresh_members_authorized_projects
end
it 'updates project authorizations so group2 and group3 users no longer have access', :aggregate_failures do
expect(group1_user.can?(:read_project, group1_project)).to eq(true)
expect(group2_user.can?(:read_project, group1_project)).to eq(true)
expect(group3_user.can?(:read_project, group1_project)).to eq(true)
destroy_group(group2, group2_user, false)
expect(group1_user.can?(:read_project, group1_project)).to eq(true)
expect(group2_user.can?(:read_project, group1_project)).to eq(false)
expect(group3_user.can?(:read_project, group1_project)).to eq(false)
end
it 'calls the service to update project authorizations only with necessary user ids' do
expect(UserProjectAccessChangedService)
.to receive(:new).with(array_including(group2_user.id, group3_user.id)).and_call_original
destroy_group(group2, group2_user, false)
end
end
end
context 'the shared_with group is deleted' do
it 'updates project authorization' do
expect(user.can?(:read_project, project)).to eq(true)
expect(user.can?(:read_project, project_child)).to eq(true)
context 'when a group is shared with a group' do
let!(:group2_project) { create(:project, :private, group: group2) }
destroy_group(shared_with_group, user, false)
expect(user.can?(:read_project, project)).to eq(false)
expect(user.can?(:read_project, project_child)).to eq(false)
before do
create(:group_group_link, shared_group: group2, shared_with_group: group1)
group1.refresh_members_authorized_projects
end
it 'makes use of a specific service to update project_authorizations records' do
expect(UserProjectAccessChangedService)
.to receive(:new).with(shared_with_group.user_ids_for_project_authorizations).and_call_original
context 'and the shared group is deleted' do
it 'updates project authorizations since the project has been deleted with the group', :aggregate_failures do
expect(group1_user.can?(:read_project, group2_project)).to eq(true)
expect(group2_user.can?(:read_project, group2_project)).to eq(true)
destroy_group(shared_with_group, user, false)
destroy_group(group2, group2_user, false)
expect(group1_user.can?(:read_project, group2_project)).to eq(false)
expect(group2_user.can?(:read_project, group2_project)).to eq(false)
end
it 'does not call the service to update project authorizations' do
expect(UserProjectAccessChangedService).not_to receive(:new)
destroy_group(group2, group2_user, false)
end
end
context 'the shared_with group is deleted' do
let!(:group2_subgroup) { create(:group, :private, parent: group2)}
let!(:group2_subgroup_project) { create(:project, :private, group: group2_subgroup) }
it 'updates project authorizations so users of both groups lose access', :aggregate_failures do
expect(group1_user.can?(:read_project, group2_project)).to eq(true)
expect(group2_user.can?(:read_project, group2_project)).to eq(true)
expect(group1_user.can?(:read_project, group2_subgroup_project)).to eq(true)
expect(group2_user.can?(:read_project, group2_subgroup_project)).to eq(true)
destroy_group(group1, group1_user, false)
expect(group1_user.can?(:read_project, group2_project)).to eq(false)
expect(group2_user.can?(:read_project, group2_project)).to eq(true)
expect(group1_user.can?(:read_project, group2_subgroup_project)).to eq(false)
expect(group2_user.can?(:read_project, group2_subgroup_project)).to eq(true)
end
it 'calls the service to update project authorizations only with necessary user ids' do
expect(UserProjectAccessChangedService)
.to receive(:new).with([group1_user.id]).and_call_original
destroy_group(group1, group1_user, false)
end
end
end
end

View File

@ -7,8 +7,10 @@ RSpec.describe JiraConnectSubscriptions::CreateService do
let(:current_user) { create(:user) }
let(:group) { create(:group) }
let(:path) { group.full_path }
let(:params) { { namespace_path: path, jira_user: jira_user } }
let(:jira_user) { double(:JiraUser, site_admin?: true) }
subject { described_class.new(installation, current_user, namespace_path: path).execute }
subject { described_class.new(installation, current_user, params).execute }
before do
group.add_maintainer(current_user)
@ -24,6 +26,30 @@ RSpec.describe JiraConnectSubscriptions::CreateService do
end
end
context 'remote user does not have access' do
let(:jira_user) { double(site_admin?: false) }
it 'does not create a subscription' do
expect { subject }.not_to change { installation.subscriptions.count }
end
it 'returns error' do
expect(subject[:status]).to eq(:error)
end
end
context 'remote user cannot be retrieved' do
let(:jira_user) { nil }
it 'does not create a subscription' do
expect { subject }.not_to change { installation.subscriptions.count }
end
it 'returns error' do
expect(subject[:status]).to eq(:error)
end
end
context 'when user does have access' do
it 'creates a subscription' do
expect { subject }.to change { installation.subscriptions.count }.from(0).to(1)

View File

@ -110,6 +110,18 @@ RSpec.describe ResourceAccessTokens::CreateService do
expect(resource.members.developers.map(&:user_id)).to include(bot_user.id)
end
end
context 'when user is external' do
let(:user) { create(:user, :external) }
before do
project.add_maintainer(user)
end
it 'creates resource bot user with external status' do
expect(subject.payload[:access_token].user.external).to eq true
end
end
end
context 'personal access token' do

View File

@ -19,7 +19,7 @@ RSpec.shared_examples 'Notes user references' do
'updated_at' => '2016-11-18T09:29:42.634Z',
'user' => {
'id' => 999,
'email' => mapped_user.email,
'public_email' => mapped_user.email,
'username' => mapped_user.username
}
}