From b132e99b27865f1e87d640ec538b282e8071ad53 Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Thu, 24 Mar 2022 03:07:39 +0000 Subject: [PATCH] Add latest changes from gitlab-org/gitlab@master --- .../list/components/issue_card_time_info.vue | 11 ++-- .../datetime/date_calculation_utility.js | 12 +++- app/models/application_setting.rb | 1 + app/services/base_container_service.rb | 4 ++ .../arkose_labs_login_challenge.yml | 8 +++ config/initializers/1_settings.rb | 8 +++ ..._grafana_config_to_application_settings.rb | 13 +++++ ...o_database_grafana_application_settings.rb | 15 +++++ db/schema_migrations/20220310011530 | 1 + db/schema_migrations/20220310011613 | 1 + db/structure.sql | 6 ++ doc/api/graphql/reference/index.md | 10 ++-- .../database/reindexing/grafana_notifier.rb | 22 +++++-- locale/gitlab.pot | 2 +- spec/controllers/sessions_controller_spec.rb | 4 ++ .../components/issue_card_time_info_spec.js | 6 +- .../datetime/date_calculation_utility_spec.js | 17 ++++++ .../reindexing/grafana_notifier_spec.rb | 58 ++++++++++++++++--- spec/models/application_setting_spec.rb | 12 ++++ 19 files changed, 183 insertions(+), 28 deletions(-) create mode 100644 config/feature_flags/development/arkose_labs_login_challenge.yml create mode 100644 db/migrate/20220310011530_add_database_grafana_config_to_application_settings.rb create mode 100644 db/migrate/20220310011613_add_text_limit_to_database_grafana_application_settings.rb create mode 100644 db/schema_migrations/20220310011530 create mode 100644 db/schema_migrations/20220310011613 create mode 100644 spec/frontend/lib/utils/datetime/date_calculation_utility_spec.js diff --git a/app/assets/javascripts/issues/list/components/issue_card_time_info.vue b/app/assets/javascripts/issues/list/components/issue_card_time_info.vue index aece7372182..1108021c7c6 100644 --- a/app/assets/javascripts/issues/list/components/issue_card_time_info.vue +++ b/app/assets/javascripts/issues/list/components/issue_card_time_info.vue @@ -6,6 +6,7 @@ import { isInFuture, isInPast, isToday, + newDateAsLocaleTime, } from '~/lib/utils/datetime_utility'; import { __ } from '~/locale'; @@ -27,7 +28,7 @@ export default { milestoneDate() { if (this.issue.milestone?.dueDate) { const { dueDate, startDate } = this.issue.milestone; - const date = dateInWords(new Date(dueDate), true); + const date = dateInWords(newDateAsLocaleTime(dueDate), true); const remainingTime = this.milestoneRemainingTime(dueDate, startDate); return `${date} (${remainingTime})`; } @@ -37,10 +38,10 @@ export default { return this.issue.milestone.webPath || this.issue.milestone.webUrl; }, dueDate() { - return this.issue.dueDate && dateInWords(new Date(this.issue.dueDate), true); + return this.issue.dueDate && dateInWords(newDateAsLocaleTime(this.issue.dueDate), true); }, showDueDateInRed() { - return isInPast(new Date(this.issue.dueDate)) && !this.issue.closedAt; + return isInPast(newDateAsLocaleTime(this.issue.dueDate)) && !this.issue.closedAt; }, timeEstimate() { return this.issue.humanTimeEstimate || this.issue.timeStats?.humanTimeEstimate; @@ -48,8 +49,8 @@ export default { }, methods: { milestoneRemainingTime(dueDate, startDate) { - const due = new Date(dueDate); - const start = new Date(startDate); + const due = newDateAsLocaleTime(dueDate); + const start = newDateAsLocaleTime(startDate); if (dueDate && isInPast(due)) { return __('Past due'); diff --git a/app/assets/javascripts/lib/utils/datetime/date_calculation_utility.js b/app/assets/javascripts/lib/utils/datetime/date_calculation_utility.js index 396c1703c1e..8dbadbe4bfc 100644 --- a/app/assets/javascripts/lib/utils/datetime/date_calculation_utility.js +++ b/app/assets/javascripts/lib/utils/datetime/date_calculation_utility.js @@ -189,13 +189,21 @@ export const getDateInFuture = (date, daysInFuture) => */ export const isValidDate = (date) => date instanceof Date && !Number.isNaN(date.getTime()); -/* +/** * Appending T00:00:00 makes JS assume local time and prevents it from shifting the date * to match the user's time zone. We want to display the date in server time for now, to * be consistent with the "edit issue -> due date" UI. + * + * @param {String} date Date without time, e.g. `2022-03-22` + * @return {Date} new Date object */ - export const newDateAsLocaleTime = (date) => { + if (!date || typeof date !== 'string') { + return null; + } + if (date.includes('T')) { + return new Date(date); + } const suffix = 'T00:00:00'; return new Date(`${date}${suffix}`); }; diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb index c7aad7ff861..23151100317 100644 --- a/app/models/application_setting.rb +++ b/app/models/application_setting.rb @@ -609,6 +609,7 @@ class ApplicationSetting < ApplicationRecord attr_encrypted :cloud_license_auth_token, encryption_options_base_32_aes_256_gcm attr_encrypted :external_pipeline_validation_service_token, encryption_options_base_32_aes_256_gcm attr_encrypted :mailgun_signing_key, encryption_options_base_32_aes_256_gcm.merge(encode: false) + attr_encrypted :database_grafana_api_key, encryption_options_base_32_aes_256_gcm.merge(encode: false, encode_iv: false) validates :disable_feed_token, inclusion: { in: [true, false], message: _('must be a boolean value') } diff --git a/app/services/base_container_service.rb b/app/services/base_container_service.rb index 190d159e7f1..86df0236a7f 100644 --- a/app/services/base_container_service.rb +++ b/app/services/base_container_service.rb @@ -26,4 +26,8 @@ class BaseContainerService def group_container? container.is_a?(::Group) end + + def namespace_container? + container.is_a?(::Namespace) + end end diff --git a/config/feature_flags/development/arkose_labs_login_challenge.yml b/config/feature_flags/development/arkose_labs_login_challenge.yml new file mode 100644 index 00000000000..74c5d625aa3 --- /dev/null +++ b/config/feature_flags/development/arkose_labs_login_challenge.yml @@ -0,0 +1,8 @@ +--- +name: arkose_labs_login_challenge +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/82751 +rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/356171 +milestone: '14.10' +type: development +group: group::antiabuse +default_enabled: false diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb index 134330144bf..3c1bc98c34a 100644 --- a/config/initializers/1_settings.rb +++ b/config/initializers/1_settings.rb @@ -989,6 +989,14 @@ Settings['prometheus'] ||= Settingslogic.new({}) Settings.prometheus['enabled'] ||= false Settings.prometheus['server_address'] ||= nil +# +# Arkose settings +# +Settings['arkose'] ||= Settingslogic.new({}) +Settings.arkose['public_key'] ||= ENV['ARKOSE_LABS_PUBLIC_KEY'] +Settings.arkose['private_key'] ||= ENV['ARKOSE_LABS_PRIVATE_KEY'] +Settings.arkose['verify_url'] ||= ENV['ARKOSE_LABS_VERIFY_URL'] + # # Shutdown settings # diff --git a/db/migrate/20220310011530_add_database_grafana_config_to_application_settings.rb b/db/migrate/20220310011530_add_database_grafana_config_to_application_settings.rb new file mode 100644 index 00000000000..7752fbba12f --- /dev/null +++ b/db/migrate/20220310011530_add_database_grafana_config_to_application_settings.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +class AddDatabaseGrafanaConfigToApplicationSettings < Gitlab::Database::Migration[1.0] + # rubocop:disable Migration/AddLimitToTextColumns + # limit is added in 20220307002607_add_text_limit_to_db_reindexing_grafana_application_settings + def change + add_column :application_settings, :encrypted_database_grafana_api_key, :binary + add_column :application_settings, :encrypted_database_grafana_api_key_iv, :binary + add_column :application_settings, :database_grafana_api_url, :text + add_column :application_settings, :database_grafana_tag, :text + end + # rubocop:enable Migration/AddLimitToTextColumns +end diff --git a/db/migrate/20220310011613_add_text_limit_to_database_grafana_application_settings.rb b/db/migrate/20220310011613_add_text_limit_to_database_grafana_application_settings.rb new file mode 100644 index 00000000000..72bcf493d6e --- /dev/null +++ b/db/migrate/20220310011613_add_text_limit_to_database_grafana_application_settings.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +class AddTextLimitToDatabaseGrafanaApplicationSettings < Gitlab::Database::Migration[1.0] + disable_ddl_transaction! + + def up + add_text_limit :application_settings, :database_grafana_api_url, 255 + add_text_limit :application_settings, :database_grafana_tag, 255 + end + + def down + remove_text_limit :application_settings, :database_grafana_tag + remove_text_limit :application_settings, :database_grafana_api_url + end +end diff --git a/db/schema_migrations/20220310011530 b/db/schema_migrations/20220310011530 new file mode 100644 index 00000000000..73fa8390231 --- /dev/null +++ b/db/schema_migrations/20220310011530 @@ -0,0 +1 @@ +a4245a3543796b48f16786e9c178f70d236b3ae4636661f021ad4e8f0c678f2c \ No newline at end of file diff --git a/db/schema_migrations/20220310011613 b/db/schema_migrations/20220310011613 new file mode 100644 index 00000000000..fc62a04f551 --- /dev/null +++ b/db/schema_migrations/20220310011613 @@ -0,0 +1 @@ +ef816d9391d67a34121d11e6b6cc37de92768bd21bc301fa10c6652b1a0b66b6 \ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index 2b7a8e5a5ba..aff8380e5b4 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -11253,6 +11253,10 @@ CREATE TABLE application_settings ( container_registry_expiration_policies_caching boolean DEFAULT true NOT NULL, search_rate_limit integer DEFAULT 30 NOT NULL, search_rate_limit_unauthenticated integer DEFAULT 10 NOT NULL, + encrypted_database_grafana_api_key bytea, + encrypted_database_grafana_api_key_iv bytea, + database_grafana_api_url text, + database_grafana_tag text, CONSTRAINT app_settings_container_reg_cleanup_tags_max_list_size_positive CHECK ((container_registry_cleanup_tags_service_max_list_size >= 0)), CONSTRAINT app_settings_dep_proxy_ttl_policies_worker_capacity_positive CHECK ((dependency_proxy_ttl_group_policy_worker_capacity >= 0)), CONSTRAINT app_settings_ext_pipeline_validation_service_url_text_limit CHECK ((char_length(external_pipeline_validation_service_url) <= 255)), @@ -11261,8 +11265,10 @@ CREATE TABLE application_settings ( CONSTRAINT app_settings_yaml_max_depth_positive CHECK ((max_yaml_depth > 0)), CONSTRAINT app_settings_yaml_max_size_positive CHECK ((max_yaml_size_bytes > 0)), CONSTRAINT check_17d9558205 CHECK ((char_length((kroki_url)::text) <= 1024)), + CONSTRAINT check_2b820eaac3 CHECK ((char_length(database_grafana_tag) <= 255)), CONSTRAINT check_2dba05b802 CHECK ((char_length(gitpod_url) <= 255)), CONSTRAINT check_32710817e9 CHECK ((char_length(static_objects_external_storage_auth_token_encrypted) <= 255)), + CONSTRAINT check_3455368420 CHECK ((char_length(database_grafana_api_url) <= 255)), CONSTRAINT check_3559645ae5 CHECK ((char_length(container_registry_import_target_plan) <= 255)), CONSTRAINT check_3def0f1829 CHECK ((char_length(sentry_clientside_dsn) <= 255)), CONSTRAINT check_4f8b811780 CHECK ((char_length(sentry_dsn) <= 255)), diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md index df68a27673e..6bdfe5bdbd4 100644 --- a/doc/api/graphql/reference/index.md +++ b/doc/api/graphql/reference/index.md @@ -4336,7 +4336,7 @@ Input type: `ScanExecutionPolicyCommitInput` ### `Mutation.securityPolicyProjectAssign` -Assigns the specified project(`security_policy_project_id`) as security policy project for the given project(`project_path`). If the project already has a security policy project, this reassigns the project's security policy project with the given `security_policy_project_id`. +Assigns the specified project(`security_policy_project_id`) as security policy project for the given project(`full_path`). If the project already has a security policy project, this reassigns the project's security policy project with the given `security_policy_project_id`. Input type: `SecurityPolicyProjectAssignInput` @@ -4345,7 +4345,8 @@ Input type: `SecurityPolicyProjectAssignInput` | Name | Type | Description | | ---- | ---- | ----------- | | `clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. | -| `projectPath` | [`ID!`](#id) | Full path of the project. | +| `fullPath` | [`String`](#string) | Full path of the project. | +| `projectPath` **{warning-solid}** | [`ID`](#id) | **Deprecated:** Use `fullPath`. Deprecated in 14.10. | | `securityPolicyProjectId` | [`ProjectID!`](#projectid) | ID of the security policy project. | #### Fields @@ -4357,7 +4358,7 @@ Input type: `SecurityPolicyProjectAssignInput` ### `Mutation.securityPolicyProjectCreate` -Creates and assigns a security policy project for the given project(`project_path`). +Creates and assigns a security policy project for the given project (`full_path`). Input type: `SecurityPolicyProjectCreateInput` @@ -4366,7 +4367,8 @@ Input type: `SecurityPolicyProjectCreateInput` | Name | Type | Description | | ---- | ---- | ----------- | | `clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. | -| `projectPath` | [`ID!`](#id) | Full path of the project. | +| `fullPath` | [`String`](#string) | Full path of the project. | +| `projectPath` **{warning-solid}** | [`ID`](#id) | **Deprecated:** Use `fullPath`. Deprecated in 14.10. | #### Fields diff --git a/lib/gitlab/database/reindexing/grafana_notifier.rb b/lib/gitlab/database/reindexing/grafana_notifier.rb index f4ea59deb50..ece9327b658 100644 --- a/lib/gitlab/database/reindexing/grafana_notifier.rb +++ b/lib/gitlab/database/reindexing/grafana_notifier.rb @@ -5,10 +5,10 @@ module Gitlab module Reindexing # This can be used to send annotations for reindexing to a Grafana API class GrafanaNotifier - def initialize(api_key = ENV['GITLAB_GRAFANA_API_KEY'], api_url = ENV['GITLAB_GRAFANA_API_URL'], additional_tag = ENV['GITLAB_REINDEXING_GRAFANA_TAG'] || Rails.env) - @api_key = api_key - @api_url = api_url - @additional_tag = additional_tag + def initialize(api_key: nil, api_url: nil, additional_tag: nil) + @api_key = api_key || default_api_key + @api_url = api_url || default_api_url + @additional_tag = additional_tag || default_additional_tag end def notify_start(action) @@ -35,10 +35,22 @@ module Gitlab private + def default_api_key + Gitlab::CurrentSettings.database_grafana_api_key || ENV['GITLAB_GRAFANA_API_KEY'] + end + + def default_api_url + Gitlab::CurrentSettings.database_grafana_api_url || ENV['GITLAB_GRAFANA_API_URL'] + end + + def default_additional_tag + Gitlab::CurrentSettings.database_grafana_tag || ENV['GITLAB_REINDEXING_GRAFANA_TAG'] || Rails.env + end + def base_payload(action) { time: (action.action_start.utc.to_f * 1000).to_i, - tags: ['reindex', @additional_tag, action.index.tablename, action.index.name].compact + tags: ['reindex', @additional_tag.presence, action.index.tablename, action.index.name].compact } end diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 00cb4029660..bc5ff475999 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -10309,7 +10309,7 @@ msgstr "" msgid "Could not upload your designs as one or more files uploaded are not supported." msgstr "" -msgid "Couldn't assign policy to project" +msgid "Couldn't assign policy to project or group" msgstr "" msgid "Country" diff --git a/spec/controllers/sessions_controller_spec.rb b/spec/controllers/sessions_controller_spec.rb index 03d053e6f97..af3850c916a 100644 --- a/spec/controllers/sessions_controller_spec.rb +++ b/spec/controllers/sessions_controller_spec.rb @@ -193,6 +193,10 @@ RSpec.describe SessionsController do end context 'with reCAPTCHA' do + before do + stub_feature_flags(arkose_labs_login_challenge: false) + end + def unsuccesful_login(user_params, sesion_params: {}) # Without this, `verify_recaptcha` arbitrarily returns true in test env Recaptcha.configuration.skip_verify_env.delete('test') diff --git a/spec/frontend/issues/list/components/issue_card_time_info_spec.js b/spec/frontend/issues/list/components/issue_card_time_info_spec.js index e9c48b60da4..c6abf7d20a3 100644 --- a/spec/frontend/issues/list/components/issue_card_time_info_spec.js +++ b/spec/frontend/issues/list/components/issue_card_time_info_spec.js @@ -4,7 +4,7 @@ import { useFakeDate } from 'helpers/fake_date'; import IssueCardTimeInfo from '~/issues/list/components/issue_card_time_info.vue'; describe('CE IssueCardTimeInfo component', () => { - useFakeDate(2020, 11, 11); + useFakeDate(2020, 11, 11); // 2020 Dec 11 let wrapper; @@ -91,7 +91,7 @@ describe('CE IssueCardTimeInfo component', () => { describe('when in the past', () => { describe('when issue is open', () => { it('renders in red', () => { - wrapper = mountComponent({ dueDate: new Date('2020-10-10') }); + wrapper = mountComponent({ dueDate: '2020-10-10' }); expect(findDueDate().classes()).toContain('gl-text-red-500'); }); @@ -100,7 +100,7 @@ describe('CE IssueCardTimeInfo component', () => { describe('when issue is closed', () => { it('does not render in red', () => { wrapper = mountComponent({ - dueDate: new Date('2020-10-10'), + dueDate: '2020-10-10', closedAt: '2020-09-05T13:06:25Z', }); diff --git a/spec/frontend/lib/utils/datetime/date_calculation_utility_spec.js b/spec/frontend/lib/utils/datetime/date_calculation_utility_spec.js new file mode 100644 index 00000000000..47bb512cbb5 --- /dev/null +++ b/spec/frontend/lib/utils/datetime/date_calculation_utility_spec.js @@ -0,0 +1,17 @@ +import { newDateAsLocaleTime } from '~/lib/utils/datetime/date_calculation_utility'; + +describe('newDateAsLocaleTime', () => { + it.each` + string | expected + ${'2022-03-22'} | ${new Date('2022-03-22T00:00:00.000Z')} + ${'2022-03-22T00:00:00.000Z'} | ${new Date('2022-03-22T00:00:00.000Z')} + ${2022} | ${null} + ${[]} | ${null} + ${{}} | ${null} + ${true} | ${null} + ${null} | ${null} + ${undefined} | ${null} + `('returns $expected given $string', ({ string, expected }) => { + expect(newDateAsLocaleTime(string)).toEqual(expected); + }); +}); diff --git a/spec/lib/gitlab/database/reindexing/grafana_notifier_spec.rb b/spec/lib/gitlab/database/reindexing/grafana_notifier_spec.rb index e76718fe48a..34670696787 100644 --- a/spec/lib/gitlab/database/reindexing/grafana_notifier_spec.rb +++ b/spec/lib/gitlab/database/reindexing/grafana_notifier_spec.rb @@ -74,8 +74,28 @@ RSpec.describe Gitlab::Database::Reindexing::GrafanaNotifier do end describe '#notify_start' do - context 'additional tag is nil' do - subject { described_class.new(api_key, api_url, nil).notify_start(action) } + context 'when Grafana is configured using application settings' do + subject { described_class.new.notify_start(action) } + + let(:payload) do + { + time: (action.action_start.utc.to_f * 1000).to_i, + tags: ['reindex', additional_tag, action.index.tablename, action.index.name], + text: "Started reindexing of #{action.index.name} on #{action.index.tablename}" + } + end + + before do + stub_application_setting(database_grafana_api_key: api_key) + stub_application_setting(database_grafana_api_url: api_url) + stub_application_setting(database_grafana_tag: additional_tag) + end + + it_behaves_like 'interacting with Grafana annotations API' + end + + context 'when there is no additional tag' do + subject { described_class.new(api_key: api_key, api_url: api_url, additional_tag: '').notify_start(action) } let(:payload) do { @@ -88,8 +108,8 @@ RSpec.describe Gitlab::Database::Reindexing::GrafanaNotifier do it_behaves_like 'interacting with Grafana annotations API' end - context 'additional tag is not nil' do - subject { described_class.new(api_key, api_url, additional_tag).notify_start(action) } + context 'additional tag is provided' do + subject { described_class.new(api_key: api_key, api_url: api_url, additional_tag: additional_tag).notify_start(action) } let(:payload) do { @@ -104,8 +124,30 @@ RSpec.describe Gitlab::Database::Reindexing::GrafanaNotifier do end describe '#notify_end' do - context 'additional tag is nil' do - subject { described_class.new(api_key, api_url, nil).notify_end(action) } + context 'when Grafana is configured using application settings' do + subject { described_class.new.notify_end(action) } + + let(:payload) do + { + time: (action.action_start.utc.to_f * 1000).to_i, + tags: ['reindex', additional_tag, action.index.tablename, action.index.name], + text: "Finished reindexing of #{action.index.name} on #{action.index.tablename} (#{action.state})", + timeEnd: (action.action_end.utc.to_f * 1000).to_i, + isRegion: true + } + end + + before do + stub_application_setting(database_grafana_api_key: api_key) + stub_application_setting(database_grafana_api_url: api_url) + stub_application_setting(database_grafana_tag: additional_tag) + end + + it_behaves_like 'interacting with Grafana annotations API' + end + + context 'when there is no additional tag' do + subject { described_class.new(api_key: api_key, api_url: api_url, additional_tag: '').notify_end(action) } let(:payload) do { @@ -120,8 +162,8 @@ RSpec.describe Gitlab::Database::Reindexing::GrafanaNotifier do it_behaves_like 'interacting with Grafana annotations API' end - context 'additional tag is not nil' do - subject { described_class.new(api_key, api_url, additional_tag).notify_end(action) } + context 'additional tag is provided' do + subject { described_class.new(api_key: api_key, api_url: api_url, additional_tag: additional_tag).notify_end(action) } let(:payload) do { diff --git a/spec/models/application_setting_spec.rb b/spec/models/application_setting_spec.rb index 70331e8d78a..dbc82e44bfc 100644 --- a/spec/models/application_setting_spec.rb +++ b/spec/models/application_setting_spec.rb @@ -1306,4 +1306,16 @@ RSpec.describe ApplicationSetting do end end end + + describe '#database_grafana_api_key' do + it 'is encrypted' do + subject.database_grafana_api_key = 'somesecret' + + aggregate_failures do + expect(subject.encrypted_database_grafana_api_key).to be_present + expect(subject.encrypted_database_grafana_api_key_iv).to be_present + expect(subject.encrypted_database_grafana_api_key).not_to eq(subject.database_grafana_api_key) + end + end + end end