提交 cfc6fe51 编写于 作者: G GitLab Bot

Add latest changes from gitlab-org/gitlab@master

上级 aca82d5b
......@@ -11,6 +11,7 @@ module Clusters
}.freeze
self.reactive_cache_key = ->(finder) { finder.model_name }
self.reactive_cache_work_type = :external_dependency
self.reactive_cache_worker_finder = ->(_id, *cache_args) { from_cache(*cache_args) }
attr_reader :cluster, :environment
......
......@@ -9,6 +9,7 @@ module Projects
attr_reader :project
self.reactive_cache_key = ->(finder) { finder.cache_key }
self.reactive_cache_work_type = :external_dependency
self.reactive_cache_worker_finder = ->(_id, *args) { from_cache(*args) }
MAX_CLUSTERS = 10
......
......@@ -26,6 +26,8 @@ module Clusters
KUBE_INGRESS_BASE_DOMAIN = 'KUBE_INGRESS_BASE_DOMAIN'
APPLICATIONS_ASSOCIATIONS = APPLICATIONS.values.map(&:association_name).freeze
self.reactive_cache_work_type = :external_dependency
belongs_to :user
belongs_to :management_project, class_name: '::Project', optional: true
......
......@@ -9,6 +9,7 @@ module PrometheusAdapter
self.reactive_cache_lease_timeout = 30.seconds
self.reactive_cache_refresh_interval = 30.seconds
self.reactive_cache_lifetime = 1.minute
self.reactive_cache_work_type = :external_dependency
def prometheus_client
raise NotImplementedError
......
......@@ -8,6 +8,7 @@ class Environment < ApplicationRecord
self.reactive_cache_refresh_interval = 1.minute
self.reactive_cache_lifetime = 55.seconds
self.reactive_cache_hard_limit = 10.megabytes
self.reactive_cache_work_type = :external_dependency
belongs_to :project, required: true
......
......@@ -22,6 +22,7 @@ module ErrorTracking
}x.freeze
self.reactive_cache_key = ->(setting) { [setting.class.model_name.singular, setting.project_id] }
self.reactive_cache_work_type = :external_dependency
belongs_to :project
......
......@@ -24,6 +24,7 @@ class SshHostKey
# This is achieved by making the lifetime shorter than the refresh interval.
self.reactive_cache_refresh_interval = 15.minutes
self.reactive_cache_lifetime = 10.minutes
self.reactive_cache_work_type = :external_dependency
def self.find_by(opts = {})
opts = HashWithIndifferentAccess.new(opts)
......
......@@ -12,6 +12,7 @@ module Grafana
self.reactive_cache_key = ->(service) { service.cache_key }
self.reactive_cache_lease_timeout = 30.seconds
self.reactive_cache_refresh_interval = 30.seconds
self.reactive_cache_work_type = :external_dependency
self.reactive_cache_worker_finder = ->(_id, *args) { from_cache(*args) }
attr_accessor :project, :datasource_id, :proxy_path, :query_params
......
......@@ -18,6 +18,7 @@ module Metrics
self.reactive_cache_lease_timeout = 30.seconds
self.reactive_cache_refresh_interval = 30.minutes
self.reactive_cache_lifetime = 30.minutes
self.reactive_cache_work_type = :external_dependency
self.reactive_cache_worker_finder = ->(_id, *args) { from_cache(*args) }
class << self
......
......@@ -11,6 +11,7 @@ module PodLogs
:pod_logs,
:filter_return_keys
self.reactive_cache_work_type = :external_dependency
self.reactive_cache_worker_finder = ->(id, _cache_key, namespace, params) { new(::Clusters::Cluster.find(id), namespace, params: params) }
private
......
......@@ -17,6 +17,7 @@ module PodLogs
:split_logs,
:filter_return_keys
self.reactive_cache_work_type = :external_dependency
self.reactive_cache_worker_finder = ->(id, _cache_key, namespace, params) { new(::Clusters::Cluster.find(id), namespace, params: params) }
private
......
......@@ -17,6 +17,7 @@ module Prometheus
# is expected to change *and* be fetched again by the frontend
self.reactive_cache_refresh_interval = 90.seconds
self.reactive_cache_lifetime = 1.minute
self.reactive_cache_work_type = :external_dependency
self.reactive_cache_worker_finder = ->(_id, *args) { from_cache(*args) }
attr_accessor :proxyable, :method, :path, :params
......
---
title: Delete orphaned rows in application_settings table
merge_request: 29981
author:
type: performance
# frozen_string_literal: true
class RemoveAdditionalApplicationSettingsRows < ActiveRecord::Migration[6.0]
class ApplicationSetting < ActiveRecord::Base
self.table_name = 'application_settings'
end
def up
return if ApplicationSetting.count == 1
execute "DELETE from application_settings WHERE id NOT IN (SELECT MAX(id) FROM application_settings);"
end
def down
# no changes
end
end
......@@ -13421,6 +13421,7 @@ COPY "schema_migrations" (version) FROM STDIN;
20200416120128
20200416120354
20200417044453
20200420162730
20200420172113
20200420172752
20200420172927
......
......@@ -223,6 +223,9 @@ This action does not delete blobs. In order to delete them and recycle disk spac
Delete registry repository tags in bulk based on given criteria.
<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
For an overview, see [Utilize the Container Registry API to delete all tags except *](https://youtu.be/Hi19bKe_xsg).
```plaintext
DELETE /projects/:id/registry/repositories/:repository_id/tags
```
......
......@@ -126,11 +126,11 @@ To start working locally on an existing remote repository, clone it with the com
files to your local computer, automatically preserving the Git connection with the
remote repository.
You can either clone it via HTTPS or [SSH](../ssh/README.md). If you chose to clone
it via HTTPS, you'll have to enter your credentials every time you pull and push.
You can either clone it via [HTTPS](#clone-via-https) or [SSH](#clone-via-ssh). If you chose to
clone it via HTTPS, you'll have to enter your credentials every time you pull and push.
You can read more about credential storage in the
[Git Credentials documentation](https://git-scm.com/book/en/v2/Git-Tools-Credential-Storage).
With SSH, you enter your credentials only once.
With [SSH](../ssh/README.md), you enter your credentials only once.
You can find both paths (HTTPS and SSH) by navigating to your project's landing page
and clicking **Clone**. GitLab will prompt you with both paths, from which you can copy
......@@ -142,24 +142,38 @@ As an example, consider this repository path:
- SSH: `git@gitlab.com:gitlab-org/gitlab.git`
To get started, open a terminal window in the directory you wish to clone the
repository files into, and run one of the following commands.
repository files into, and run one of the `git clone` commands as described below.
Clone via HTTPS:
Both commands will download a copy of the files in a folder named after the project's
name. You can then navigate to the new directory and start working on it locally.
#### Clone via HTTPS
To clone `https://gitlab.com/gitlab-org/gitlab.git` via HTTPS:
```shell
git clone https://gitlab.com/gitlab-org/gitlab.git
```
Clone via SSH:
You'll have to add your password every time you clone through HTTPS. If you have 2FA enabled
for your account, you'll have to use a [Personal Access Token](../user/profile/personal_access_tokens.md)
with **read_repository** or **write_repository** permissions instead of your account's password.
If you don't have 2FA enabled, use your account's password.
TIP: **Troubleshooting:**
On Windows, if you entered incorrect passwords multiple times and GitLab is responding `Access denied`,
you may have to add your namespace (user name or group name) to clone through HTTPS:
`git clone https://namespace@gitlab.com/gitlab-org/gitlab.git`.
#### Clone via SSH
To clone `git@gitlab.com:gitlab-org/gitlab.git` via SSH:
```shell
git clone git@gitlab.com:gitlab-org/gitlab.git
```
Both commands will download a copy of the files in a folder named after the project's
name. You can then navigate to the directory and start working
on it locally.
### Switch to the master branch
You are always in a branch when working with Git. The main branch is the master
......
......@@ -17,7 +17,7 @@ When working within HAML (or Vue templates) we can add `data-track-*` attributes
Below is an example of `data-track-*` attributes assigned to a button:
```haml
%button.btn{ data: { track: { event: "click_button", label: "template_preview", property: "my-template" } } }
%button.btn{ data: { track_event: "click_button", track_label: "template_preview", track_property: "my-template" } }
```
```html
......
......@@ -189,6 +189,9 @@ Once you've set up your identity provider to work with GitLab, you'll need to co
![Group SAML Settings for GitLab.com](img/group_saml_settings.png)
NOTE: **Note:**
Please note that the certificate [fingerprint algorithm](#additional-setup-options) must be in SHA1. When configuring the identity provider, use a secure [signature algorithm](#additional-setup-options).
## User access and management
Once Group SSO is configured and enabled, users can access the GitLab.com group through the identity provider's dashboard. If [SCIM](scim_setup.md) is configured, please see the [user access and linking setup section on the SCIM page](scim_setup.md#user-access-and-linking-setup).
......
......@@ -12,25 +12,28 @@ that group is synchronized between GitLab and the identity provider.
GitLab's [SCIM API](../../../api/scim.md) implements part of [the RFC7644 protocol](https://tools.ietf.org/html/rfc7644).
## Features
Currently, the following actions are available:
- CREATE
- UPDATE
- DELETE (deprovisioning)
- Create users
- Update users (Azure only)
- Deactivate users
The following identity providers are supported:
- Azure
- Okta
## Requirements
- [Group SSO](index.md) must be configured.
- [Group Single Sign-On](index.md) must be configured.
## GitLab configuration
Once [Single sign-on](index.md) has been configured, we can:
Once [Group Single Sign-On](index.md) has been configured, we can:
1. Navigate to the group and click **Settings > SAML SSO**.
1. Navigate to the group and click **Administration > SAML SSO**.
1. Click on the **Generate a SCIM token** button.
1. Save the token and URL so they can be used in the next step.
......@@ -38,9 +41,12 @@ Once [Single sign-on](index.md) has been configured, we can:
## Identity Provider configuration
### Azure
- [Azure](#azure-configuration-steps)
- [Okta](#okta-configuration-steps)
The SAML application that was created during [Single sign-on](index.md) setup now needs to be set up for SCIM.
### Azure configuration steps
The SAML application that was created during [Single sign-on](index.md) setup for [Azure](https://docs.microsoft.com/en-us/azure/active-directory/manage-apps/configure-single-sign-on-non-gallery-applications) now needs to be set up for SCIM.
1. Check the configuration for your GitLab SAML app and ensure that **Name identifier value** (NameID) points to `user.objectid` or another unique identifier. This will match the `extern_uid` used on GitLab.
......@@ -109,6 +115,38 @@ bottom of the **Provisioning** screen, together with a link to the audit logs.
CAUTION: **Warning:**
Once synchronized, changing the field mapped to `id` and `externalId` will likely cause provisioning errors, duplicate users, and prevent existing users from accessing the GitLab group.
### Okta configuration steps
The SAML application that was created during [Single sign-on](index.md) setup for [Okta](The SAML application that was created during [Single sign-on](index.md) setup for [Okta](https://developer.okta.com/docs/guides/saml-application-setup/overview/) now needs to be set up for SCIM.
1. Sign in to Okta.
1. If you see an **Admin** button in the top right, click the button. This will
ensure you are in the Admin area.
TIP: **Tip:** If you're using the Developer Console, click **Developer Console** in the top
bar and select **Classic UI**. Otherwise, you may not see the buttons described
in the following steps:
1. In the **Application** tab, click **Add Application**.
1. Search for **GitLab**, find and click on the 'GitLab' application.
1. On the GitLab application overview page, click **Add**.
1. Under **Application Visibility** select both check boxes. Currently the GitLab application does not support SAML authentication so the icon should not be shown to users.
1. Click **Done** to finish adding the application.
1. In the **Provisioning** tab, click **Configure API integration**.
1. Select **Enable API integration**.
- For **Base URL** enter the URL obtained from the GitLab SCIM configuration page
- For **API Token** enter the SCIM token obtained from the GitLab SCIM configuration page
1. Click 'Test API Credentials' to verify configuration.
1. Click **Save** to apply the settings.
1. Assign users in the **Assignments** tab. Assigned users will be created and
managed in your GitLab group.
#### Okta Known Issues
The Okta GitLab application currently only supports SCIM. Continue
using the separate Okta [SAML SSO](index.md) configuration along with the new SCIM
application described above.
## User access and linking setup
As long as [Group SAML](index.md) has been configured, prior to turning on sync, existing GitLab.com users can link to their accounts in one of the following ways, before synchronization is active:
......@@ -135,7 +173,9 @@ Upon the next sync, the user will be deprovisioned, which means that the user wi
This section contains possible solutions for problems you might encounter.
### How do I verify my SCIM configuration is correct?
### Azure
#### How do I verify my SCIM configuration is correct?
Review the following:
......@@ -148,11 +188,11 @@ Review the following SCIM parameters for sensible values:
- `displayName`
- `emails[type eq "work"].value`
### Testing Azure connection: invalid credentials
#### Testing Azure connection: invalid credentials
When testing the connection, you may encounter an error: **You appear to have entered invalid credentials. Please confirm you are using the correct information for an administrative account**. If `Tenant URL` and `secret token` are correct, check whether your group path contains characters that may be considered invalid JSON primitives (such as `.`). Removing such characters from the group path typically resolves the error.
### Azure: (Field) can't be blank sync error
#### Azure: (Field) can't be blank sync error
When checking the Audit Logs for the Provisioning, you can sometimes see the
error `Namespace can't be blank, Name can't be blank, and User can't be blank.`
......@@ -165,14 +205,7 @@ As a workaround, try an alternate mapping:
1. Delete the `name.formatted` target attribute entry.
1. Change the `displayName` source attribute to have `name.formatted` target attribute.
### Message: "SAML authentication failed: Email has already been taken"
This message may be caused by the following:
- Existing users have not yet signed into the new app.
- The identity provider attempts to create a new user account in GitLab with an email address that already exists in GitLab.com.
### How do I diagnose why a user is unable to sign in
#### How do I diagnose why a user is unable to sign in
The **Identity** (`extern_uid`) value stored by GitLab is updated by SCIM whenever `id` or `externalId` changes. Users won't be able to sign in unless the GitLab Identity (`extern_uid`) value matches the `NameId` sent by SAML.
......@@ -180,7 +213,7 @@ This value is also used by SCIM to match users on the `id`, and is updated by SC
It is important that this SCIM `id` and SCIM `externalId` are configured to the same value as the SAML `NameId`. SAML responses can be traced using [debugging tools](./index.md#saml-debugging-tools), and any errors can be checked against our [SAML troubleshooting docs](./index.md#troubleshooting).
### How do I verify user's SAML NameId matches the SCIM externalId
#### How do I verify user's SAML NameId matches the SCIM externalId
Group owners can see the list of users and the `externalId` stored for each user in the group SAML SSO Settings page.
......@@ -194,7 +227,7 @@ curl 'https://example.gitlab.com/api/scim/v2/groups/GROUP_NAME/Users?startIndex=
To see how this compares to the value returned as the SAML NameId, you can have the user use a [SAML Tracer](index.md#saml-debugging-tools).
### Update or fix mismatched SCIM externalId and SAML NameId
#### Update or fix mismatched SCIM externalId and SAML NameId
Whether the value was changed or you need to map to a different field, ensure `id`, `externalId`, and `NameId` all map to the same field.
......@@ -220,7 +253,7 @@ curl --verbose --request PATCH 'https://gitlab.com/api/scim/v2/groups/YOUR_GROUP
It is important not to update these to incorrect values, since this will cause users to be unable to sign in. It is also important not to assign a value to the wrong user, as this would cause users to get signed into the wrong account.
### I need to change my SCIM app
#### I need to change my SCIM app
Individual users can follow the instructions in the ["SAML authentication failed: User has already been taken"](./index.md#i-need-to-change-my-saml-app) section.
......
......@@ -189,7 +189,7 @@ describe Projects::MirrorsController do
context 'no data in cache' do
it 'requests the cache to be filled and returns a 204 response' do
expect(ReactiveCachingWorker).to receive(:perform_async).with(cache.class, cache.id).at_least(:once)
expect(ExternalServiceReactiveCachingWorker).to receive(:perform_async).with(cache.class, cache.id).at_least(:once)
do_get(project)
......
# frozen_string_literal: true
require 'spec_helper'
require Rails.root.join('db', 'post_migrate', '20200420162730_remove_additional_application_settings_rows.rb')
describe RemoveAdditionalApplicationSettingsRows do
let(:application_settings) { table(:application_settings) }
it 'removes additional rows from application settings' do
3.times { application_settings.create! }
latest_settings = application_settings.create!
disable_migrations_output { migrate! }
expect(application_settings.count).to eq(1)
expect(application_settings.first).to eq(latest_settings)
end
it 'leaves only row in application_settings' do
latest_settings = application_settings.create!
disable_migrations_output { migrate! }
expect(application_settings.first).to eq(latest_settings)
end
end
......@@ -66,7 +66,7 @@ describe Grafana::ProxyService do
context 'with caching', :use_clean_rails_memory_store_caching do
context 'when value not present in cache' do
it 'returns nil' do
expect(ReactiveCachingWorker)
expect(ExternalServiceReactiveCachingWorker)
.to receive(:perform_async)
.with(service.class, service.id, *cache_params)
......
......@@ -154,7 +154,7 @@ describe Metrics::Dashboard::GrafanaMetricEmbedService do
context 'when value not present in cache' do
it 'returns nil' do
expect(ReactiveCachingWorker)
expect(ExternalServiceReactiveCachingWorker)
.to receive(:perform_async)
.with(service.class, service.id, *cache_params)
......
......@@ -117,7 +117,7 @@ describe Prometheus::ProxyService do
context 'when value not present in cache' do
it 'returns nil' do
expect(ReactiveCachingWorker)
expect(ExternalServiceReactiveCachingWorker)
.to receive(:perform_async)
.with(subject.class, subject.id, *opts)
......
......@@ -246,12 +246,19 @@ module GraphqlHelpers
# Raises an error if no data is found
def graphql_data
# Note that `json_response` is defined as `let(:json_response)` and
# therefore, in a spec with multiple queries, will only contain data
# from the _first_ query, not subsequent ones
json_response['data'] || (raise NoData, graphql_errors)
end
def graphql_data_at(*path)
graphql_dig_at(graphql_data, *path)
end
def graphql_dig_at(data, *path)
keys = path.map { |segment| GraphqlHelpers.fieldnamerize(segment) }
graphql_data.dig(*keys)
data.dig(*keys)
end
def graphql_errors
......
# frozen_string_literal: true
# Use this for testing how a GraphQL query handles sorting and pagination.
# This is particularly important when using keyset pagination connection,
# which is the default for ActiveRecord relations, as certain sort keys
# might not be supportable.
#
# sort_param: the value to specify the sort
# data_path: the keys necessary to dig into the return GraphQL data to get the
# returned results
# first_param: number of items expected (like a page size)
# expected_results: array of comparison data of all items sorted correctly
# pagination_query: method that specifies the GraphQL query
# pagination_results_data: method that extracts the sorted data used to compare against
# the expected results
#
# Example:
# describe 'sorting and pagination' do
# let(:sort_project) { create(:project, :public) }
# let(:data_path) { [:project, :issues] }
#
# def pagination_query(params, page_info)
# graphql_query_for(
# 'project',
# { 'fullPath' => sort_project.full_path },
# "issues(#{params}) { #{page_info} edges { node { iid weight } } }"
# )
# end
#
# def pagination_results_data(data)
# data.map { |issue| issue.dig('node', 'iid').to_i }
# end
#
# context 'when sorting by weight' do
# ...
# context 'when ascending' do
# it_behaves_like 'sorted paginated query' do
# let(:sort_param) { 'WEIGHT_ASC' }
# let(:first_param) { 2 }
# let(:expected_results) { [weight_issue3.iid, weight_issue5.iid, weight_issue1.iid, weight_issue4.iid, weight_issue2.iid] }
# end
# end
#
RSpec.shared_examples 'sorted paginated query' do
it_behaves_like 'requires variables' do
let(:required_variables) { [:sort_param, :first_param, :expected_results, :data_path, :current_user] }
end
describe do
let(:params) { "sort: #{sort_param}" }
let(:start_cursor) { graphql_data_at(*data_path, :pageInfo, :startCursor) }
let(:end_cursor) { graphql_data_at(*data_path, :pageInfo, :endCursor) }
let(:sorted_edges) { graphql_data_at(*data_path, :edges) }
let(:page_info) { "pageInfo { startCursor endCursor }" }
def pagination_query(params, page_info)
raise('pagination_query(params, page_info) must be defined in the test, see example in comment') unless defined?(super)
super
end
def pagination_results_data(data)
raise('pagination_results_data(data) must be defined in the test, see example in comment') unless defined?(super)
super(data)
end
before do
post_graphql(pagination_query(params, page_info), current_user: current_user)
end
context 'when sorting' do
it 'sorts correctly' do
expect(pagination_results_data(sorted_edges)).to eq expected_results
end
context 'when paginating' do
let(:params) { "sort: #{sort_param}, first: #{first_param}" }
it 'paginates correctly' do
expect(pagination_results_data(sorted_edges)).to eq expected_results.first(first_param)
cursored_query = pagination_query("sort: #{sort_param}, after: \"#{end_cursor}\"", page_info)
post_graphql(cursored_query, current_user: current_user)
response_data = graphql_dig_at(JSON.parse(response.body), :data, *data_path, :edges)
expect(pagination_results_data(response_data)).to eq expected_results.drop(first_param)
end
end
end
end
end
# frozen_string_literal: true
RSpec.shared_examples 'requires variables' do
it 'shared example requires variables to be set', :aggregate_failures do
variables = Array.wrap(required_variables)
variables.each do |variable_name|
expect { send(variable_name) }.not_to(
raise_error, "The following variable must be set to use this shared example: #{variable_name}"
)
end
end
end
......@@ -786,10 +786,10 @@
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.121.0.tgz#77083a68f72e9aa0e294da7715f378eef13b839e"
integrity sha512-scz/6Y/eED7RMFLAlhT6PwXwe0Wj8ivnRsyulk9NXKoqUmAqZliNmBmzYsHy5bFf9NB6xVV/rOk1/92nbi/Yaw==
"@gitlab/ui@12.2.0":
version "12.2.0"
resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-12.2.0.tgz#2dc6103ef4eeb016cdff8a885bee173ed3eab5f3"
integrity sha512-Qkyzrcu28gfJy635kqgfXzIKndOMT6touZ32FlXYowyrJOBQOxQt1q4/Z+S6nDWkC0tbBuOsbGiPx6F37MjWjQ==
"@gitlab/ui@12.3.0":
version "12.3.0"
resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-12.3.0.tgz#9234205887675a6d13a51945ee62efc3c8b5e890"
integrity sha512-XrHC2pK7qlwy6K3OR/+iCP8TDewn3jaDIHCfHjt/KOwvD5LsEmam9RHjTiZ4epPZXLv4+JxCzbc4R+euEbIQ7g==
dependencies:
"@babel/standalone" "^7.0.0"
"@gitlab/vue-toasted" "^1.3.0"
......@@ -1036,10 +1036,10 @@
"@sentry/types" "5.10.0"
tslib "^1.9.3"
"@sourcegraph/code-host-integration@0.0.36":
version "0.0.36"
resolved "https://registry.yarnpkg.com/@sourcegraph/code-host-integration/-/code-host-integration-0.0.36.tgz#2f4d287840ac2944c78ef92f10f0db0ef8a077fa"
integrity sha512-Hpj1xiVhPxMsjLNre9MrYYAM1SPOWPE9yG9SPtz4dqYzc6/ycaPGyr+ljcaWEclS9hZCvkk4+qVC5WONpYVjyA==
"@sourcegraph/code-host-integration@0.0.37":
version "0.0.37"
resolved "https://registry.yarnpkg.com/@sourcegraph/code-host-integration/-/code-host-integration-0.0.37.tgz#87f9a602e2a60520b6038311a67face2ece86827"
integrity sha512-GQvNuPORLjsMhto57Ue1umeSV3cir+hMEaGxwCKmmq+cc9ZSZpuXa8RVBXuT5azN99K9/8zFps4woyPJ8wrjYA==
"@types/anymatch@*":
version "1.3.0"
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册