Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/assets/javascripts/boards/components/board_form.vue6
-rw-r--r--app/assets/javascripts/boards/components/boards_selector.vue3
-rw-r--r--app/assets/javascripts/boards/mount_multiple_boards_switcher.js15
-rw-r--r--app/assets/javascripts/google_cloud/index.js12
-rw-r--r--app/assets/javascripts/graphql_shared/utils.js4
-rw-r--r--app/controllers/projects/google_cloud_controller.rb5
-rw-r--r--app/services/google_cloud/service_accounts_service.rb40
-rw-r--r--app/views/projects/google_cloud/index.html.haml2
-rw-r--r--config/initializers/database_query_analyzers.rb4
-rw-r--r--doc/ci/yaml/index.md48
-rw-r--r--doc/user/group/saml_sso/index.md5
-rw-r--r--lib/gitlab/database/load_balancing/load_balancer.rb4
-rw-r--r--lib/gitlab/database/load_balancing/sidekiq_server_middleware.rb10
-rw-r--r--lib/gitlab/database/query_analyzer.rb2
-rw-r--r--spec/frontend/graphql_shared/utils_spec.js52
-rw-r--r--spec/lib/gitlab/database/query_analyzer_spec.rb2
-rw-r--r--spec/services/google_cloud/service_accounts_service_spec.rb58
17 files changed, 166 insertions, 106 deletions
diff --git a/app/assets/javascripts/boards/components/board_form.vue b/app/assets/javascripts/boards/components/board_form.vue
index 45381ab1021..6ad57fd8985 100644
--- a/app/assets/javascripts/boards/components/board_form.vue
+++ b/app/assets/javascripts/boards/components/board_form.vue
@@ -2,7 +2,7 @@
import { GlModal, GlAlert } from '@gitlab/ui';
import { mapGetters, mapActions, mapState } from 'vuex';
import { TYPE_USER, TYPE_ITERATION, TYPE_MILESTONE } from '~/graphql_shared/constants';
-import { convertToGraphQLId, getZeroBasedIdFromGraphQLId } from '~/graphql_shared/utils';
+import { convertToGraphQLId, getIdFromGraphQLId } from '~/graphql_shared/utils';
import { getParameterByName, visitUrl } from '~/lib/utils/url_utility';
import { __, s__ } from '~/locale';
import { fullLabelId } from '../boards_util';
@@ -169,11 +169,11 @@ export default {
: null,
// Temporarily converting to milestone ID due to https://gitlab.com/gitlab-org/gitlab/-/issues/344779
milestoneId: this.board.milestone?.id
- ? convertToGraphQLId(TYPE_MILESTONE, getZeroBasedIdFromGraphQLId(this.board.milestone.id))
+ ? convertToGraphQLId(TYPE_MILESTONE, getIdFromGraphQLId(this.board.milestone.id))
: null,
// Temporarily converting to iteration ID due to https://gitlab.com/gitlab-org/gitlab/-/issues/344779
iterationId: this.board.iteration?.id
- ? convertToGraphQLId(TYPE_ITERATION, getZeroBasedIdFromGraphQLId(this.board.iteration.id))
+ ? convertToGraphQLId(TYPE_ITERATION, getIdFromGraphQLId(this.board.iteration.id))
: null,
};
},
diff --git a/app/assets/javascripts/boards/components/boards_selector.vue b/app/assets/javascripts/boards/components/boards_selector.vue
index 2f2ac5409e0..71facba1378 100644
--- a/app/assets/javascripts/boards/components/boards_selector.vue
+++ b/app/assets/javascripts/boards/components/boards_selector.vue
@@ -268,12 +268,11 @@ export default {
<template>
<div class="boards-switcher js-boards-selector gl-mr-3">
<span class="boards-selector-wrapper js-boards-selector-wrapper">
- <gl-loading-icon v-if="isBoardLoading" size="md" class="gl-mt-2" />
<gl-dropdown
- v-else
data-qa-selector="boards_dropdown"
toggle-class="dropdown-menu-toggle js-dropdown-toggle"
menu-class="flex-column dropdown-extended-height"
+ :loading="isBoardLoading"
:text="board.name"
@show="loadBoards"
>
diff --git a/app/assets/javascripts/boards/mount_multiple_boards_switcher.js b/app/assets/javascripts/boards/mount_multiple_boards_switcher.js
index 26dd8b99f98..ed32579a9c3 100644
--- a/app/assets/javascripts/boards/mount_multiple_boards_switcher.js
+++ b/app/assets/javascripts/boards/mount_multiple_boards_switcher.js
@@ -1,14 +1,27 @@
+import { IntrospectionFragmentMatcher } from 'apollo-cache-inmemory';
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import BoardsSelector from 'ee_else_ce/boards/components/boards_selector.vue';
import store from '~/boards/stores';
import createDefaultClient from '~/lib/graphql';
import { parseBoolean } from '~/lib/utils/common_utils';
+import introspectionQueryResultData from '~/sidebar/fragmentTypes.json';
Vue.use(VueApollo);
+const fragmentMatcher = new IntrospectionFragmentMatcher({
+ introspectionQueryResultData,
+});
+
const apolloProvider = new VueApollo({
- defaultClient: createDefaultClient(),
+ defaultClient: createDefaultClient(
+ {},
+ {
+ cacheConfig: {
+ fragmentMatcher,
+ },
+ },
+ ),
});
export default (params = {}) => {
diff --git a/app/assets/javascripts/google_cloud/index.js b/app/assets/javascripts/google_cloud/index.js
index a2838605219..a156a632e9a 100644
--- a/app/assets/javascripts/google_cloud/index.js
+++ b/app/assets/javascripts/google_cloud/index.js
@@ -6,14 +6,6 @@ const elementRenderer = (element, props = {}) => (createElement) =>
export default () => {
const root = document.querySelector('#js-google-cloud');
-
- // uncomment this once backend is ready
- // const dataset = JSON.parse(root.getAttribute('data'));
- const mockDataset = {
- createServiceAccountUrl: '#create-url',
- serviceAccounts: [],
- emptyIllustrationUrl:
- 'https://gitlab.com/gitlab-org/gitlab-svgs/-/raw/main/illustrations/pipelines_empty.svg',
- };
- return new Vue({ el: root, render: elementRenderer(App, mockDataset) });
+ const props = JSON.parse(root.getAttribute('data'));
+ return new Vue({ el: root, render: elementRenderer(App, props) });
};
diff --git a/app/assets/javascripts/graphql_shared/utils.js b/app/assets/javascripts/graphql_shared/utils.js
index e459ebf629f..8fb70eb59bd 100644
--- a/app/assets/javascripts/graphql_shared/utils.js
+++ b/app/assets/javascripts/graphql_shared/utils.js
@@ -25,9 +25,7 @@ const parseGid = (gid) => parseInt(`${gid}`.replace(/gid:\/\/gitlab\/.*\//g, '')
* @param {String} gid GraphQL global ID
* @returns {Number}
*/
-export const getIdFromGraphQLId = (gid = '') => parseGid(gid) || null;
-
-export const getZeroBasedIdFromGraphQLId = (gid = '') => {
+export const getIdFromGraphQLId = (gid = '') => {
const parsedGid = parseGid(gid);
return Number.isInteger(parsedGid) ? parsedGid : null;
};
diff --git a/app/controllers/projects/google_cloud_controller.rb b/app/controllers/projects/google_cloud_controller.rb
index c62b80fe7ac..7257ed1ef6f 100644
--- a/app/controllers/projects/google_cloud_controller.rb
+++ b/app/controllers/projects/google_cloud_controller.rb
@@ -8,6 +8,11 @@ class Projects::GoogleCloudController < Projects::ApplicationController
before_action :feature_flag_enabled?
def index
+ @js_data = {
+ serviceAccounts: GoogleCloud::ServiceAccountsService.new(project).find_for_project,
+ createServiceAccountUrl: '#mocked-url-create-service',
+ emptyIllustrationUrl: ActionController::Base.helpers.image_path('illustrations/pipelines_empty.svg')
+ }.to_json
end
private
diff --git a/app/services/google_cloud/service_accounts_service.rb b/app/services/google_cloud/service_accounts_service.rb
new file mode 100644
index 00000000000..29ed69693b0
--- /dev/null
+++ b/app/services/google_cloud/service_accounts_service.rb
@@ -0,0 +1,40 @@
+# frozen_string_literal: true
+
+module GoogleCloud
+ ##
+ # GCP keys used to store Google Cloud Service Accounts
+ GCP_KEYS = %w[GCP_PROJECT_ID GCP_SERVICE_ACCOUNT GCP_SERVICE_ACCOUNT_KEY].freeze
+
+ ##
+ # This service deals with GCP Service Accounts in GitLab
+
+ class ServiceAccountsService < ::BaseService
+ ##
+ # Find GCP Service Accounts in a GitLab project
+ #
+ # This method looks up GitLab project's CI vars
+ # and returns Google Cloud Service Accounts combinations
+ # aligning GitLab project and environment to GCP projects
+
+ def find_for_project
+ group_vars_by_environment.map do |environment_scope, value|
+ {
+ environment: environment_scope,
+ gcp_project: value['GCP_PROJECT_ID'],
+ service_account_exists: value['GCP_SERVICE_ACCOUNT'].present?,
+ service_account_key_exists: value['GCP_SERVICE_ACCOUNT_KEY'].present?
+ }
+ end
+ end
+
+ private
+
+ def group_vars_by_environment
+ filtered_vars = @project.variables.filter { |variable| GCP_KEYS.include? variable.key }
+ filtered_vars.each_with_object({}) do |variable, grouped|
+ grouped[variable.environment_scope] ||= {}
+ grouped[variable.environment_scope][variable.key] = variable.value
+ end
+ end
+ end
+end
diff --git a/app/views/projects/google_cloud/index.html.haml b/app/views/projects/google_cloud/index.html.haml
index 72736327988..69e481501d5 100644
--- a/app/views/projects/google_cloud/index.html.haml
+++ b/app/views/projects/google_cloud/index.html.haml
@@ -3,4 +3,4 @@
- @content_class = "limit-container-width" unless fluid_layout
-#js-google-cloud
+#js-google-cloud{ data: @js_data }
diff --git a/config/initializers/database_query_analyzers.rb b/config/initializers/database_query_analyzers.rb
index a29cd6552ff..7d4802b76c2 100644
--- a/config/initializers/database_query_analyzers.rb
+++ b/config/initializers/database_query_analyzers.rb
@@ -1,4 +1,6 @@
# frozen_string_literal: true
# Currently we register validator only for `dev` or `test` environment
-Gitlab::Database::QueryAnalyzer.new.hook! if Gitlab.dev_or_test_env?
+if Gitlab.dev_or_test_env? || Gitlab::Utils.to_boolean(ENV['GITLAB_ENABLE_QUERY_ANALYZERS'], default: false)
+ Gitlab::Database::QueryAnalyzer.instance.hook!
+end
diff --git a/doc/ci/yaml/index.md b/doc/ci/yaml/index.md
index ec135661a60..9458fe650bc 100644
--- a/doc/ci/yaml/index.md
+++ b/doc/ci/yaml/index.md
@@ -2599,33 +2599,12 @@ faster-test-job:
- echo "Running tests..."
```
-### `artifacts`
-
-Use `artifacts` to specify a list of files and directories that are
-attached to the job when it [succeeds, fails, or always](#artifactswhen).
-
-The artifacts are sent to GitLab after the job finishes. They are
-available for download in the GitLab UI if the size is not
-larger than the [maximum artifact size](../../user/gitlab_com/index.md#gitlab-cicd).
-
-By default, jobs in later stages automatically download all the artifacts created
-by jobs in earlier stages. You can control artifact download behavior in jobs with
-[`dependencies`](#dependencies).
-
-When using the [`needs`](#artifact-downloads-with-needs) keyword, jobs can only download
-artifacts from the jobs defined in the `needs` configuration.
-
-Job artifacts are only collected for successful jobs by default, and
-artifacts are restored after [caches](#cache).
-
-[Read more about artifacts](../pipelines/job_artifacts.md).
-
-#### `dependencies`
+### `dependencies`
-Use the `dependencies` keyword to define a list of jobs to fetch artifacts from.
+Use the `dependencies` keyword to define a list of jobs to fetch [artifacts](#artifacts) from.
You can also set a job to download no artifacts at all.
-If you do not use `dependencies`, all `artifacts` from previous stages are passed to each job.
+If you do not use `dependencies`, all artifacts from previous stages are passed to each job.
**Keyword type**: Job keyword. You can use it only as part of a job.
@@ -2681,6 +2660,27 @@ the [stage](#stages) precedence.
- If the artifacts of a dependent job are [expired](#artifactsexpire_in) or
[deleted](../pipelines/job_artifacts.md#delete-job-artifacts), then the job fails.
+### `artifacts`
+
+Use `artifacts` to specify a list of files and directories that are
+attached to the job when it [succeeds, fails, or always](#artifactswhen).
+
+The artifacts are sent to GitLab after the job finishes. They are
+available for download in the GitLab UI if the size is not
+larger than the [maximum artifact size](../../user/gitlab_com/index.md#gitlab-cicd).
+
+By default, jobs in later stages automatically download all the artifacts created
+by jobs in earlier stages. You can control artifact download behavior in jobs with
+[`dependencies`](#dependencies).
+
+When using the [`needs`](#artifact-downloads-with-needs) keyword, jobs can only download
+artifacts from the jobs defined in the `needs` configuration.
+
+Job artifacts are only collected for successful jobs by default, and
+artifacts are restored after [caches](#cache).
+
+[Read more about artifacts](../pipelines/job_artifacts.md).
+
#### `artifacts:exclude`
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/15122) in GitLab 13.1
diff --git a/doc/user/group/saml_sso/index.md b/doc/user/group/saml_sso/index.md
index 8c837f86065..402007b85b2 100644
--- a/doc/user/group/saml_sso/index.md
+++ b/doc/user/group/saml_sso/index.md
@@ -118,8 +118,9 @@ SSO has the following effects when enabled:
- For groups, users can't share a project in the group outside the top-level group,
even if the project is forked.
-- For a Git activity, users must be signed-in through SSO before they can push to or
- pull from a GitLab repository.
+- For Git activity over SSH and HTTPS, users must have at least one active session signed-in through SSO before they can push to or
+ pull from a GitLab repository.
+- Credentials that are not tied to regular users (for example, access tokens and deploy keys) do not have the SSO check enforced.
- Users must be signed-in through SSO before they can pull images using the [Dependency Proxy](../../packages/dependency_proxy/index.md).
<!-- Add bullet for API activity when https://gitlab.com/gitlab-org/gitlab/-/issues/9152 is complete -->
diff --git a/lib/gitlab/database/load_balancing/load_balancer.rb b/lib/gitlab/database/load_balancing/load_balancer.rb
index 78059ef00f8..1dc39abcf1e 100644
--- a/lib/gitlab/database/load_balancing/load_balancer.rb
+++ b/lib/gitlab/database/load_balancing/load_balancer.rb
@@ -66,7 +66,7 @@ module Gitlab
# times before using the primary instead.
will_retry = conflict_retried < @host_list.length * 3
- LoadBalancing::Logger.warn(
+ ::Gitlab::Database::LoadBalancing::Logger.warn(
event: :host_query_conflict,
message: 'Query conflict on host',
conflict_retried: conflict_retried,
@@ -91,7 +91,7 @@ module Gitlab
end
end
- LoadBalancing::Logger.warn(
+ ::Gitlab::Database::LoadBalancing::Logger.warn(
event: :no_secondaries_available,
message: 'No secondaries were available, using primary instead',
conflict_retried: conflict_retried,
diff --git a/lib/gitlab/database/load_balancing/sidekiq_server_middleware.rb b/lib/gitlab/database/load_balancing/sidekiq_server_middleware.rb
index f0c7016032b..b9acc36b4cc 100644
--- a/lib/gitlab/database/load_balancing/sidekiq_server_middleware.rb
+++ b/lib/gitlab/database/load_balancing/sidekiq_server_middleware.rb
@@ -13,7 +13,7 @@ module Gitlab
job['load_balancing_strategy'] = strategy.to_s
if use_primary?(strategy)
- Session.current.use_primary!
+ ::Gitlab::Database::LoadBalancing::Session.current.use_primary!
elsif strategy == :retry
raise JobReplicaNotUpToDate, "Sidekiq job #{worker_class} JID-#{job['jid']} couldn't use the replica."\
" Replica was not up to date."
@@ -29,8 +29,8 @@ module Gitlab
private
def clear
- LoadBalancing.release_hosts
- Session.clear_session
+ ::Gitlab::Database::LoadBalancing.release_hosts
+ ::Gitlab::Database::LoadBalancing::Session.clear_session
end
def use_primary?(strategy)
@@ -66,7 +66,7 @@ module Gitlab
def legacy_wal_location(job)
wal_location = job['database_write_location'] || job['database_replica_location']
- { Gitlab::Database::MAIN_DATABASE_NAME.to_sym => wal_location } if wal_location
+ { ::Gitlab::Database::MAIN_DATABASE_NAME.to_sym => wal_location } if wal_location
end
def load_balancing_available?(worker_class)
@@ -90,7 +90,7 @@ module Gitlab
end
def databases_in_sync?(wal_locations)
- LoadBalancing.each_load_balancer.all? do |lb|
+ ::Gitlab::Database::LoadBalancing.each_load_balancer.all? do |lb|
if (location = wal_locations[lb.name])
lb.select_up_to_date_host(location)
else
diff --git a/lib/gitlab/database/query_analyzer.rb b/lib/gitlab/database/query_analyzer.rb
index 830ad1383c0..6cbeefa0aae 100644
--- a/lib/gitlab/database/query_analyzer.rb
+++ b/lib/gitlab/database/query_analyzer.rb
@@ -5,6 +5,8 @@ module Gitlab
# The purpose of this class is to implement a various query analyzers based on `pg_query`
# And process them all via `Gitlab::Database::QueryAnalyzers::*`
class QueryAnalyzer
+ include ::Singleton
+
ANALYZERS = [].freeze
Parsed = Struct.new(
diff --git a/spec/frontend/graphql_shared/utils_spec.js b/spec/frontend/graphql_shared/utils_spec.js
index 4dffb4dc73a..9f478eedbfb 100644
--- a/spec/frontend/graphql_shared/utils_spec.js
+++ b/spec/frontend/graphql_shared/utils_spec.js
@@ -1,7 +1,6 @@
import {
isGid,
getIdFromGraphQLId,
- getZeroBasedIdFromGraphQLId,
convertToGraphQLId,
convertToGraphQLIds,
convertFromGraphQLIds,
@@ -54,7 +53,7 @@ describe('getIdFromGraphQLId', () => {
},
{
input: 'gid://gitlab/Environments/0',
- output: null,
+ output: 0,
},
{
input: 'gid://gitlab/Environments/123',
@@ -71,55 +70,6 @@ describe('getIdFromGraphQLId', () => {
});
});
-describe('getZeroBasedIdFromGraphQLId', () => {
- [
- {
- input: '',
- output: null,
- },
- {
- input: null,
- output: null,
- },
- {
- input: 2,
- output: 2,
- },
- {
- input: 'gid://',
- output: null,
- },
- {
- input: 'gid://gitlab/',
- output: null,
- },
- {
- input: 'gid://gitlab/Environments',
- output: null,
- },
- {
- input: 'gid://gitlab/Environments/',
- output: null,
- },
- {
- input: 'gid://gitlab/Environments/0',
- output: 0,
- },
- {
- input: 'gid://gitlab/Environments/123',
- output: 123,
- },
- {
- input: 'gid://gitlab/DesignManagement::Version/2',
- output: 2,
- },
- ].forEach(({ input, output }) => {
- it(`getZeroBasedIdFromGraphQLId returns ${output} when passed ${input}`, () => {
- expect(getZeroBasedIdFromGraphQLId(input)).toBe(output);
- });
- });
-});
-
describe('convertToGraphQLId', () => {
it('combines $type and $id into $result', () => {
expect(convertToGraphQLId(mockType, mockId)).toBe(mockGid);
diff --git a/spec/lib/gitlab/database/query_analyzer_spec.rb b/spec/lib/gitlab/database/query_analyzer_spec.rb
index 3567bd6a058..f0a3021927b 100644
--- a/spec/lib/gitlab/database/query_analyzer_spec.rb
+++ b/spec/lib/gitlab/database/query_analyzer_spec.rb
@@ -65,7 +65,7 @@ RSpec.describe Gitlab::Database::QueryAnalyzer do
def process_sql(sql)
ApplicationRecord.load_balancer.read_write do |connection|
- described_class.new.send(:process_sql, sql, connection)
+ described_class.instance.send(:process_sql, sql, connection)
end
end
end
diff --git a/spec/services/google_cloud/service_accounts_service_spec.rb b/spec/services/google_cloud/service_accounts_service_spec.rb
new file mode 100644
index 00000000000..a0d09affa72
--- /dev/null
+++ b/spec/services/google_cloud/service_accounts_service_spec.rb
@@ -0,0 +1,58 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe GoogleCloud::ServiceAccountsService do
+ let_it_be(:project) { create(:project) }
+
+ let(:service) { described_class.new(project) }
+
+ describe 'find_for_project' do
+ context 'when a project does not have GCP service account vars' do
+ before do
+ project.variables.build(key: 'blah', value: 'foo', environment_scope: 'world')
+ project.save!
+ end
+
+ it 'returns an empty list' do
+ expect(service.find_for_project.length).to eq(0)
+ end
+ end
+
+ context 'when a project has GCP service account ci vars' do
+ before do
+ project.variables.build(environment_scope: '*', key: 'GCP_PROJECT_ID', value: 'prj1')
+ project.variables.build(environment_scope: '*', key: 'GCP_SERVICE_ACCOUNT_KEY', value: 'mock')
+ project.variables.build(environment_scope: 'staging', key: 'GCP_PROJECT_ID', value: 'prj2')
+ project.variables.build(environment_scope: 'staging', key: 'GCP_SERVICE_ACCOUNT', value: 'mock')
+ project.variables.build(environment_scope: 'production', key: 'GCP_PROJECT_ID', value: 'prj3')
+ project.variables.build(environment_scope: 'production', key: 'GCP_SERVICE_ACCOUNT', value: 'mock')
+ project.variables.build(environment_scope: 'production', key: 'GCP_SERVICE_ACCOUNT_KEY', value: 'mock')
+ project.save!
+ end
+
+ it 'returns a list of service accounts' do
+ list = service.find_for_project
+
+ aggregate_failures 'testing list of service accounts' do
+ expect(list.length).to eq(3)
+
+ expect(list.first[:environment]).to eq('*')
+ expect(list.first[:gcp_project]).to eq('prj1')
+ expect(list.first[:service_account_exists]).to eq(false)
+ expect(list.first[:service_account_key_exists]).to eq(true)
+
+ expect(list.second[:environment]).to eq('staging')
+ expect(list.second[:gcp_project]).to eq('prj2')
+ expect(list.second[:service_account_exists]).to eq(true)
+ expect(list.second[:service_account_key_exists]).to eq(false)
+
+ expect(list.third[:environment]).to eq('production')
+ expect(list.third[:gcp_project]).to eq('prj3')
+ expect(list.third[:service_account_exists]).to eq(true)
+ expect(list.third[:service_account_key_exists]).to eq(true)
+ end
+ end
+ end
+ end
+end