Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
34d6e7c91b
commit
d9115c7779
41
CHANGELOG.md
41
CHANGELOG.md
|
@ -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)
|
||||
|
|
2
Gemfile
2
Gemfile
|
@ -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)
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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) => ({
|
||||
|
|
|
@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -20,4 +20,8 @@ class JiraConnectInstallation < ApplicationRecord
|
|||
id: JiraConnectSubscription.for_project(project)
|
||||
})
|
||||
}
|
||||
|
||||
def client
|
||||
Atlassian::JiraConnect::Client.new(base_url, shared_secret)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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:
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'apollo_upload_server'
|
||||
|
||||
ApolloUploadServer::Middleware.strict_mode = true
|
|
@ -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
|
|
@ -0,0 +1 @@
|
|||
f6f5e081672fb42adde980fa12f696f5d8fd11921ee52c1472b3d745bb11a5ff
|
|
@ -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",
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -259,7 +259,7 @@ Only include the following attributes for the models specified:
|
|||
included_attributes:
|
||||
user:
|
||||
- :id
|
||||
- :email
|
||||
- :public_email
|
||||
# ...
|
||||
```
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -20,7 +20,7 @@ tree:
|
|||
included_attributes:
|
||||
user:
|
||||
- :id
|
||||
- :email
|
||||
- :public_email
|
||||
- :username
|
||||
author:
|
||||
- :name
|
||||
|
|
|
@ -20,7 +20,7 @@ tree:
|
|||
included_attributes:
|
||||
user:
|
||||
- :id
|
||||
- :email
|
||||
- :public_email
|
||||
- :username
|
||||
author:
|
||||
- :name
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -115,7 +115,7 @@ tree:
|
|||
included_attributes:
|
||||
user:
|
||||
- :id
|
||||
- :email
|
||||
- :public_email
|
||||
- :username
|
||||
author:
|
||||
- :name
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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') }
|
||||
|
|
|
@ -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
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"}}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"}}
|
||||
|
|
|
@ -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"}}
|
||||
|
|
|
@ -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"}}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"}}
|
||||
|
|
|
@ -33,8 +33,6 @@ describe('Pipelines filtered search', () => {
|
|||
};
|
||||
|
||||
beforeEach(() => {
|
||||
window.gon = { features: { pipelineSourceFilter: true } };
|
||||
|
||||
mock = new MockAdapter(axios);
|
||||
|
||||
jest.spyOn(Api, 'projectUsers').mockResolvedValue(users);
|
||||
|
|
|
@ -105,8 +105,6 @@ describe('Pipelines', () => {
|
|||
});
|
||||
|
||||
beforeEach(() => {
|
||||
window.gon = { features: { pipelineSourceFilter: true } };
|
||||
|
||||
mock = new MockAdapter(axios);
|
||||
|
||||
jest.spyOn(window.history, 'pushState');
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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 }
|
||||
|
||||
|
|
|
@ -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) }
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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))
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue