diff options
33 files changed, 342 insertions, 504 deletions
diff --git a/app/assets/javascripts/sidebar/components/move/move_issue_button.vue b/app/assets/javascripts/sidebar/components/move/move_issue_button.vue index 76c47305369..581537264db 100644 --- a/app/assets/javascripts/sidebar/components/move/move_issue_button.vue +++ b/app/assets/javascripts/sidebar/components/move/move_issue_button.vue @@ -26,10 +26,11 @@ export default { }, }, methods: { - moveIssue(targetProject) { + async moveIssue(targetProject) { this.moveInProgress = true; - return this.$apollo - .mutate({ + + try { + const { data } = await this.$apollo.mutate({ mutation: moveIssueMutation, variables: { moveIssueInput: { @@ -38,24 +39,25 @@ export default { targetProjectPath: targetProject.full_path, }, }, - }) - .then(({ data = {} }) => { - if (!data.issueMove) return; + }); + + if (!data.issueMove) return; + + const { errors } = data.issueMove; + if (errors?.length > 0) { + throw new Error(`Error moving the issue. Error message: ${errors[0].message}`); + } - const { errors } = data.issueMove; - if (errors?.length > 0) { - throw new Error(`Error moving the issue. Error message: ${errors[0].message}`); - } - visitUrl(data.issueMove?.issue.webUrl); - }) - .catch((error) => { - this.moveInProgress = false; - createAlert({ - message: this.$options.i18n.moveErrorMessage, - captureError: true, - error, - }); + visitUrl(data.issueMove?.issue.webUrl); + } catch (error) { + createAlert({ + message: this.$options.i18n.moveErrorMessage, + captureError: true, + error, }); + } finally { + this.moveInProgress = false; + } }, }, }; diff --git a/app/helpers/broadcast_messages_helper.rb b/app/helpers/broadcast_messages_helper.rb index 1c5a601de25..bc3527565a6 100644 --- a/app/helpers/broadcast_messages_helper.rb +++ b/app/helpers/broadcast_messages_helper.rb @@ -79,6 +79,23 @@ module BroadcastMessagesHelper end.to_json end + def broadcast_message_data(broadcast_message) + { + id: broadcast_message.id, + message: broadcast_message.message, + broadcast_type: broadcast_message.broadcast_type, + theme: broadcast_message.theme, + dismissable: broadcast_message.dismissable.to_s, + target_access_levels: broadcast_message.target_access_levels, + messages_path: admin_broadcast_messages_path, + preview_path: preview_admin_broadcast_messages_path, + target_path: broadcast_message.target_path, + starts_at: broadcast_message.starts_at.iso8601, + ends_at: broadcast_message.ends_at.iso8601, + target_access_level_options: target_access_level_options.to_json + } + end + private def current_user_access_level_for_project_or_group diff --git a/app/helpers/clusters_helper.rb b/app/helpers/clusters_helper.rb index 8449bccd285..5d554f57cc0 100644 --- a/app/helpers/clusters_helper.rb +++ b/app/helpers/clusters_helper.rb @@ -37,7 +37,6 @@ module ClustersHelper editable: can_edit.to_s, environment_scope: cluster.environment_scope, base_domain: cluster.base_domain, - application_ingress_external_ip: cluster.application_ingress_external_ip, auto_devops_help_path: help_page_path('topics/autodevops/index'), external_endpoint_help_path: help_page_path('user/project/clusters/gitlab_managed_clusters.md', anchor: 'base-domain') } diff --git a/app/models/clusters/applications/ingress.rb b/app/models/clusters/applications/ingress.rb deleted file mode 100644 index 034b178d67d..00000000000 --- a/app/models/clusters/applications/ingress.rb +++ /dev/null @@ -1,91 +0,0 @@ -# frozen_string_literal: true - -module Clusters - module Applications - # DEPRECATED for removal in %14.0 - # See https://gitlab.com/groups/gitlab-org/-/epics/4280 - class Ingress < ApplicationRecord - VERSION = '1.40.2' - INGRESS_CONTAINER_NAME = 'nginx-ingress-controller' - - self.table_name = 'clusters_applications_ingress' - - include ::Clusters::Concerns::ApplicationCore - include ::Clusters::Concerns::ApplicationStatus - include ::Clusters::Concerns::ApplicationVersion - include ::Clusters::Concerns::ApplicationData - include AfterCommitQueue - include UsageStatistics - - attribute :version, default: VERSION - - enum ingress_type: { - nginx: 1 - }, _default: :nginx - - FETCH_IP_ADDRESS_DELAY = 30.seconds - - state_machine :status do - after_transition any => [:installed] do |application| - application.run_after_commit do - ClusterWaitForIngressIpAddressWorker.perform_in( - FETCH_IP_ADDRESS_DELAY, application.name, application.id) - end - end - end - - def chart - "#{name}/nginx-ingress" - end - - def repository - 'https://gitlab-org.gitlab.io/cluster-integration/helm-stable-archive' - end - - def values - content_values.to_yaml - end - - def allowed_to_uninstall? - external_ip_or_hostname? && !application_jupyter_installed? - end - - def install_command - helm_command_module::InstallCommand.new( - name: name, - repository: repository, - version: VERSION, - rbac: cluster.platform_kubernetes_rbac?, - chart: chart, - files: files - ) - end - - def external_ip_or_hostname? - external_ip.present? || external_hostname.present? - end - - def schedule_status_update - return unless installed? - return if external_ip - return if external_hostname - - ClusterWaitForIngressIpAddressWorker.perform_async(name, id) - end - - def ingress_service - cluster.kubeclient.get_service("ingress-#{INGRESS_CONTAINER_NAME}", Gitlab::Kubernetes::Helm::NAMESPACE) - end - - private - - def content_values - YAML.load_file(chart_values_file) - end - - def application_jupyter_installed? - cluster.application_jupyter&.installed? - end - end - end -end diff --git a/app/models/clusters/cluster.rb b/app/models/clusters/cluster.rb index d4e1de44042..d8e5c351d10 100644 --- a/app/models/clusters/cluster.rb +++ b/app/models/clusters/cluster.rb @@ -12,8 +12,7 @@ module Clusters self.table_name = 'clusters' APPLICATIONS = { - Clusters::Applications::Helm.application_name => Clusters::Applications::Helm, - Clusters::Applications::Ingress.application_name => Clusters::Applications::Ingress + Clusters::Applications::Helm.application_name => Clusters::Applications::Helm }.freeze DEFAULT_ENVIRONMENT = '*' KUBE_INGRESS_BASE_DOMAIN = 'KUBE_INGRESS_BASE_DOMAIN' @@ -50,7 +49,6 @@ module Clusters end has_one_cluster_application :helm - has_one_cluster_application :ingress has_many :kubernetes_namespaces has_many :metrics_dashboard_annotations, class_name: 'Metrics::Dashboard::Annotation', inverse_of: :cluster @@ -78,9 +76,6 @@ module Clusters delegate :status, to: :provider, allow_nil: true delegate :status_reason, to: :provider, allow_nil: true - delegate :external_ip, to: :application_ingress, prefix: true, allow_nil: true - delegate :external_hostname, to: :application_ingress, prefix: true, allow_nil: true - alias_attribute :base_domain, :domain alias_attribute :provided_by_user?, :user? @@ -264,10 +259,6 @@ module Clusters !!application_helm&.available? end - def application_ingress_available? - !!application_ingress&.available? - end - def integration_prometheus_available? !!integration_prometheus&.available? end diff --git a/app/views/admin/broadcast_messages/edit.html.haml b/app/views/admin/broadcast_messages/edit.html.haml index a85702f562a..63ce08eef85 100644 --- a/app/views/admin/broadcast_messages/edit.html.haml +++ b/app/views/admin/broadcast_messages/edit.html.haml @@ -2,17 +2,4 @@ - breadcrumb_title @broadcast_message.id - page_title _("Broadcast Messages") -#js-broadcast-message{ data: { - id: @broadcast_message.id, - message: @broadcast_message.message, - broadcast_type: @broadcast_message.broadcast_type, - theme: @broadcast_message.theme, - dismissable: @broadcast_message.dismissable.to_s, - target_access_levels: @broadcast_message.target_access_levels, - messages_path: admin_broadcast_messages_path, - preview_path: preview_admin_broadcast_messages_path, - target_path: @broadcast_message.target_path, - starts_at: @broadcast_message.starts_at, - ends_at: @broadcast_message.ends_at, - target_access_level_options: target_access_level_options.to_json, -} } +#js-broadcast-message{ data: broadcast_message_data(@broadcast_message) } diff --git a/config/feature_flags/development/ci_remove_post_lint.yml b/config/feature_flags/development/ci_remove_post_lint.yml new file mode 100644 index 00000000000..0c3eff2c0be --- /dev/null +++ b/config/feature_flags/development/ci_remove_post_lint.yml @@ -0,0 +1,8 @@ +--- +name: ci_remove_post_lint +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/116256 +rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/403256 +milestone: '15.11' +type: development +group: group::pipeline authoring +default_enabled: false diff --git a/db/docs/clusters_applications_ingress.yml b/db/docs/clusters_applications_ingress.yml index 02dda5a4498..7970448369e 100644 --- a/db/docs/clusters_applications_ingress.yml +++ b/db/docs/clusters_applications_ingress.yml @@ -1,7 +1,5 @@ --- table_name: clusters_applications_ingress -classes: -- Clusters::Applications::Ingress feature_categories: - kubernetes_management description: "(Deprecated) A GitLab managed Ingress installation in a Kubernetes cluster" diff --git a/doc/development/testing_guide/testing_levels.md b/doc/development/testing_guide/testing_levels.md index 187d30c12be..2a5c303217f 100644 --- a/doc/development/testing_guide/testing_levels.md +++ b/doc/development/testing_guide/testing_levels.md @@ -366,7 +366,6 @@ See also: - The [RSpec testing guidelines](../testing_guide/best_practices.md#rspec). - System / Feature tests in the [Testing Best Practices](best_practices.md#system--feature-tests). -- [Issue #26159](https://gitlab.com/gitlab-org/gitlab/-/issues/26159) which aims at combining those guidelines with this page. ```mermaid graph RL diff --git a/doc/user/admin_area/settings/usage_statistics.md b/doc/user/admin_area/settings/usage_statistics.md index 89c240a853e..c216b2b2fb3 100644 --- a/doc/user/admin_area/settings/usage_statistics.md +++ b/doc/user/admin_area/settings/usage_statistics.md @@ -199,6 +199,11 @@ To upload the payload manually: The uploaded file is encrypted and sent using secure HTTPS protocol. HTTPS creates a secure communication channel between web browser and the server, and protects transmitted data against man-in-the-middle attacks. +If there are problems with the manual upload: + +1. Open a confidential issue in the [security fork of version app project](https://gitlab.com/gitlab-org/security/version.gitlab.com). +1. Attach the JSON payload if possible. +1. Tag `@gitlab-org/analytics-section/product-intelligence` who will triage the issue. <!-- ## Troubleshooting Include any troubleshooting steps that you can foresee. If you know beforehand what issues diff --git a/doc/user/project/import/github.md b/doc/user/project/import/github.md index a1d94d81e69..e9ae12fbde5 100644 --- a/doc/user/project/import/github.md +++ b/doc/user/project/import/github.md @@ -80,10 +80,9 @@ Before you begin, ensure that any GitHub user you want to map to a GitLab user h [publicly visible email address](https://docs.github.com/en/rest/users#get-a-user) on GitHub. If you are importing to GitLab.com, you can alternatively import GitHub repositories using a [personal access token](#use-a-github-token). -We do not recommend this method, as it does not associate all user activity (such as issues and pull requests) with matching GitLab users. -User-matching attempts occur in that order, and if a user is not identified either way, the activity is associated with -the user account that is performing the import. +If a GitHub user's public email address doesn't match any GitLab user email address, the user's activity is associated with the user account that is +performing the import. NOTE: If you are using a self-managed GitLab instance or if you are importing from GitHub Enterprise, this process requires that you have configured @@ -101,9 +100,7 @@ Prerequisite: - Authentication token with administrator access. -Using a personal access token to import projects is not recommended. If you are a GitLab.com user, -you can use a personal access token to import your project from GitHub, but this method cannot -associate all user activity (such as issues and pull requests) with matching GitLab users. +If you are a GitLab.com user, you can use a personal access token to import your project from GitHub. If you are an administrator of a self-managed GitLab instance or if you are importing from GitHub Enterprise, you cannot use a personal access token. The [GitHub integration method (above)](#use-the-github-integration) is recommended for all users. diff --git a/doc/user/project/repository/reducing_the_repo_size_using_git.md b/doc/user/project/repository/reducing_the_repo_size_using_git.md index cf7d4f44aad..4bebe4c1a97 100644 --- a/doc/user/project/repository/reducing_the_repo_size_using_git.md +++ b/doc/user/project/repository/reducing_the_repo_size_using_git.md @@ -22,16 +22,27 @@ Rewriting repository history is a destructive operation. Make sure to back up yo you begin. The best way to back up a repository is to [export the project](../settings/import_export.md#export-a-project-and-its-data). +## Calculate repository size + +The size of a repository is determined by computing the accumulated size of all files in the repository. +It is similar to executing `du --summarize --bytes` on your repository's +[hashed storage path](../../../administration/repository_storage_types.md). + ## Purge files from repository history -To reduce the size of your repository in GitLab, you must first remove references to large files from branches, tags, *and* -other internal references (refs) that are automatically created by GitLab. These refs include: +GitLab [prunes unreachable objects](../../../administration/housekeeping.md#prune-unreachable-objects) +as part of housekeeping. In GitLab, to reduce the disk size of your repository manually, you must +first remove references to large files from branches, tags, *and* other internal references (refs) +created by GitLab. These refs include: -- `refs/merge-requests/*` for merge requests. -- `refs/pipelines/*` for - [pipelines](../../../ci/troubleshooting.md#fatal-reference-is-not-a-tree-error). -- `refs/environments/*` for environments. -- `refs/keep-around/*` are created as hidden refs to prevent commits referenced in the database from being removed +- `refs/merge-requests/*` +- `refs/pipelines/*` +- `refs/environments/*` +- `refs/keep-around/*` + +NOTE: +For details on each of these references, see +[GitLab-specific references](../../../development/gitaly.md#gitlab-specific-references). These refs are not automatically downloaded and hidden refs are not advertised, but we can remove these refs using a project export. diff --git a/lib/api/branches.rb b/lib/api/branches.rb index 5ae1a80a7fd..c5ea3a2d3ad 100644 --- a/lib/api/branches.rb +++ b/lib/api/branches.rb @@ -14,7 +14,7 @@ module API before do require_repository_enabled! - authorize! :read_code, user_project + authorize_read_code! end rescue_from Gitlab::Git::Repository::NoRepository do diff --git a/lib/api/commits.rb b/lib/api/commits.rb index f884dde3552..7a86c995f1a 100644 --- a/lib/api/commits.rb +++ b/lib/api/commits.rb @@ -9,7 +9,7 @@ module API before do require_repository_enabled! - authorize! :read_code, user_project + authorize_read_code! verify_pagination_params! end diff --git a/lib/api/files.rb b/lib/api/files.rb index 1850413caa6..45e935d7ea2 100644 --- a/lib/api/files.rb +++ b/lib/api/files.rb @@ -30,7 +30,7 @@ module API end def assign_file_vars! - authorize! :read_code, user_project + authorize_read_code! @commit = user_project.commit(params[:ref]) not_found!('Commit') unless @commit diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index 74c740f47cc..e55452fd07b 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -332,6 +332,10 @@ module API authorize! :read_build, user_project end + def authorize_read_code! + authorize! :read_code, user_project + end + def authorize_read_build_trace!(build) authorize! :read_build_trace, build end diff --git a/lib/api/lint.rb b/lib/api/lint.rb index 0dd06d27aeb..15ccf0da0b9 100644 --- a/lib/api/lint.rb +++ b/lib/api/lint.rb @@ -28,6 +28,7 @@ module API end post '/lint', urgency: :low do + render_api_error!('410 Gone', 410) unless Feature.disabled?(:ci_remove_post_lint, current_user) unauthorized! unless can_lint_ci? result = Gitlab::Ci::Lint.new(project: nil, current_user: current_user) @@ -56,7 +57,7 @@ module API end get ':id/ci/lint', urgency: :low do - authorize! :read_code, user_project + authorize_read_code! if user_project.commit.present? content = user_project.repository.gitlab_ci_yml_for(user_project.commit.id, user_project.ci_config_path_or_default) diff --git a/lib/api/protected_branches.rb b/lib/api/protected_branches.rb index a50208d78d7..3d9abe23638 100644 --- a/lib/api/protected_branches.rb +++ b/lib/api/protected_branches.rb @@ -6,8 +6,6 @@ module API BRANCH_ENDPOINT_REQUIREMENTS = API::NAMESPACE_OR_PROJECT_REQUIREMENTS.merge(name: API::NO_SLASH_URL_PART_REGEX) - before { authorize_admin_project } - feature_category :source_code_management helpers Helpers::ProtectedBranchesHelpers @@ -33,6 +31,8 @@ module API end # rubocop: disable CodeReuse/ActiveRecord get ':id/protected_branches' do + authorize_read_code! + protected_branches = ProtectedBranchesFinder .new(user_project, params) @@ -55,6 +55,8 @@ module API end # rubocop: disable CodeReuse/ActiveRecord get ':id/protected_branches/:name', requirements: BRANCH_ENDPOINT_REQUIREMENTS do + authorize_read_code! + protected_branch = user_project.protected_branches.find_by!(name: params[:name]) present protected_branch, with: Entities::ProtectedBranch, project: user_project @@ -86,6 +88,8 @@ module API end # rubocop: disable CodeReuse/ActiveRecord post ':id/protected_branches' do + authorize_admin_project + protected_branch = user_project.protected_branches.find_by(name: params[:name]) if protected_branch @@ -123,6 +127,8 @@ module API end # rubocop: disable CodeReuse/ActiveRecord patch ':id/protected_branches/:name', requirements: BRANCH_ENDPOINT_REQUIREMENTS do + authorize_admin_project + protected_branch = user_project.protected_branches.find_by!(name: params[:name]) declared_params = declared_params(include_missing: false) @@ -150,6 +156,8 @@ module API end # rubocop: disable CodeReuse/ActiveRecord delete ':id/protected_branches/:name', requirements: BRANCH_ENDPOINT_REQUIREMENTS, urgency: :low do + authorize_admin_project + protected_branch = user_project.protected_branches.find_by!(name: params[:name]) destroy_conditionally!(protected_branch) do diff --git a/lib/api/releases.rb b/lib/api/releases.rb index ebf1c03e86b..0b31a3e0309 100644 --- a/lib/api/releases.rb +++ b/lib/api/releases.rb @@ -387,10 +387,6 @@ module API authorize! :download_code, user_project end - def authorize_read_code! - authorize! :read_code, user_project - end - def authorize_create_evidence! # extended in EE end diff --git a/lib/api/repositories.rb b/lib/api/repositories.rb index 6f8d34ea387..295d1d5ab16 100644 --- a/lib/api/repositories.rb +++ b/lib/api/repositories.rb @@ -41,7 +41,7 @@ module API end end - before { authorize! :read_code, user_project } + before { authorize_read_code! } feature_category :source_code_management @@ -63,7 +63,7 @@ module API end def assign_blob_vars!(limit:) - authorize! :read_code, user_project + authorize_read_code! @repo = user_project.repository diff --git a/lib/api/tags.rb b/lib/api/tags.rb index f918fb997bf..42b63af59e0 100644 --- a/lib/api/tags.rb +++ b/lib/api/tags.rb @@ -7,7 +7,7 @@ module API TAG_ENDPOINT_REQUIREMENTS = API::NAMESPACE_OR_PROJECT_REQUIREMENTS.merge(tag_name: API::NO_SLASH_URL_PART_REGEX) before do - authorize! :read_code, user_project + authorize_read_code! not_found! unless user_project.repo_exists? end diff --git a/spec/controllers/admin/clusters_controller_spec.rb b/spec/controllers/admin/clusters_controller_spec.rb index 8e62aeed7d0..cb310c7b7f9 100644 --- a/spec/controllers/admin/clusters_controller_spec.rb +++ b/spec/controllers/admin/clusters_controller_spec.rb @@ -259,14 +259,6 @@ RSpec.describe Admin::ClustersController, feature_category: :kubernetes_manageme expect(response).to have_gitlab_http_status(:ok) expect(response).to match_response_schema('cluster_status') end - - it 'invokes schedule_status_update on each application' do - expect_next_instance_of(Clusters::Applications::Ingress) do |instance| - expect(instance).to receive(:schedule_status_update) - end - - get_cluster_status - end end describe 'security' do diff --git a/spec/controllers/groups/clusters_controller_spec.rb b/spec/controllers/groups/clusters_controller_spec.rb index 01ea7101f2e..c020aeedf1c 100644 --- a/spec/controllers/groups/clusters_controller_spec.rb +++ b/spec/controllers/groups/clusters_controller_spec.rb @@ -322,12 +322,6 @@ RSpec.describe Groups::ClustersController, feature_category: :kubernetes_managem expect(response).to have_gitlab_http_status(:ok) expect(response).to match_response_schema('cluster_status') end - - it 'invokes schedule_status_update on each application' do - expect_any_instance_of(Clusters::Applications::Ingress).to receive(:schedule_status_update) - - go - end end describe 'security' do diff --git a/spec/controllers/projects/clusters_controller_spec.rb b/spec/controllers/projects/clusters_controller_spec.rb index d16e5eea2e9..236e1845d3f 100644 --- a/spec/controllers/projects/clusters_controller_spec.rb +++ b/spec/controllers/projects/clusters_controller_spec.rb @@ -358,12 +358,6 @@ RSpec.describe Projects::ClustersController, feature_category: :kubernetes_manag expect(response).to have_gitlab_http_status(:ok) expect(response).to match_response_schema('cluster_status') end - - it 'invokes schedule_status_update on each application' do - expect_any_instance_of(Clusters::Applications::Ingress).to receive(:schedule_status_update) - - go - end end describe 'security' do diff --git a/spec/db/schema_spec.rb b/spec/db/schema_spec.rb index ca0d54abca7..f73edeed3c3 100644 --- a/spec/db/schema_spec.rb +++ b/spec/db/schema_spec.rb @@ -207,7 +207,6 @@ RSpec.describe 'Database schema', feature_category: :database do 'Ci::Processable' => %w[failure_reason], 'Ci::Runner' => %w[access_level], 'Ci::Stage' => %w[status], - 'Clusters::Applications::Ingress' => %w[ingress_type], 'Clusters::Cluster' => %w[platform_type provider_type], 'CommitStatus' => %w[failure_reason], 'GenericCommitStatus' => %w[failure_reason], diff --git a/spec/factories/clusters/applications/helm.rb b/spec/factories/clusters/applications/helm.rb index 67cd0de5c4f..4cf7023b5aa 100644 --- a/spec/factories/clusters/applications/helm.rb +++ b/spec/factories/clusters/applications/helm.rb @@ -93,9 +93,5 @@ FactoryBot.define do helm_installed { false } end end - - factory :clusters_applications_ingress, class: 'Clusters::Applications::Ingress' do - cluster factory: %i(cluster with_installed_helm provided_by_gcp) - end end end diff --git a/spec/factories/clusters/clusters.rb b/spec/factories/clusters/clusters.rb index 0525b569e50..e50240aee7e 100644 --- a/spec/factories/clusters/clusters.rb +++ b/spec/factories/clusters/clusters.rb @@ -92,7 +92,6 @@ FactoryBot.define do trait :with_all_applications do application_helm factory: %i(clusters_applications_helm installed) - application_ingress factory: %i(clusters_applications_ingress installed) end trait :with_domain do diff --git a/spec/frontend/sidebar/components/move/move_issue_button_spec.js b/spec/frontend/sidebar/components/move/move_issue_button_spec.js index eb5e23c6047..e2f5414056a 100644 --- a/spec/frontend/sidebar/components/move/move_issue_button_spec.js +++ b/spec/frontend/sidebar/components/move/move_issue_button_spec.js @@ -71,10 +71,6 @@ describe('MoveIssueButton', () => { }); }; - afterEach(() => { - fakeApollo = null; - }); - it('renders the project select dropdown', () => { createComponent(); diff --git a/spec/helpers/broadcast_messages_helper_spec.rb b/spec/helpers/broadcast_messages_helper_spec.rb index e0bdb09f257..8d2245c820f 100644 --- a/spec/helpers/broadcast_messages_helper_spec.rb +++ b/spec/helpers/broadcast_messages_helper_spec.rb @@ -157,4 +157,24 @@ RSpec.describe BroadcastMessagesHelper, feature_category: :onboarding do expect(single_broadcast_message['ends_at']).to eq('2020-01-02T00:00:00Z') end end + + describe '#broadcast_message_data' do + let(:starts_at) { 1.day.ago } + let(:ends_at) { 1.day.from_now } + let(:message) { build(:broadcast_message, id: non_existing_record_id, starts_at: starts_at, ends_at: ends_at) } + + it 'returns the expected message data attributes' do + keys = [ + :id, :message, :broadcast_type, :theme, :dismissable, :target_access_levels, :messages_path, + :preview_path, :target_path, :starts_at, :ends_at, :target_access_level_options + ] + + expect(broadcast_message_data(message).keys).to match(keys) + end + + it 'has the correct iso formatted date', time_travel_to: '2020-01-01 00:00:00 +0000' do + expect(broadcast_message_data(message)[:starts_at]).to eq('2019-12-31T00:00:00Z') + expect(broadcast_message_data(message)[:ends_at]).to eq('2020-01-02T00:00:00Z') + end + end end diff --git a/spec/models/clusters/applications/ingress_spec.rb b/spec/models/clusters/applications/ingress_spec.rb deleted file mode 100644 index 99be2ed8ee8..00000000000 --- a/spec/models/clusters/applications/ingress_spec.rb +++ /dev/null @@ -1,120 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Clusters::Applications::Ingress do - let(:ingress) { create(:clusters_applications_ingress) } - - before do - allow(ClusterWaitForIngressIpAddressWorker).to receive(:perform_in) - allow(ClusterWaitForIngressIpAddressWorker).to receive(:perform_async) - end - - it_behaves_like 'having unique enum values' - - include_examples 'cluster application core specs', :clusters_applications_ingress - include_examples 'cluster application status specs', :clusters_applications_ingress - include_examples 'cluster application version specs', :clusters_applications_ingress - include_examples 'cluster application helm specs', :clusters_applications_ingress - include_examples 'cluster application initial status specs' - - describe 'default values' do - it { expect(subject.ingress_type).to eq("nginx") } - it { expect(subject.version).to eq(described_class::VERSION) } - end - - describe '#make_installed!' do - before do - application.make_installed! - end - - let(:application) { create(:clusters_applications_ingress, :installing) } - - it 'schedules a ClusterWaitForIngressIpAddressWorker' do - expect(ClusterWaitForIngressIpAddressWorker).to have_received(:perform_in) - .with(Clusters::Applications::Ingress::FETCH_IP_ADDRESS_DELAY, 'ingress', application.id) - end - end - - describe '#schedule_status_update' do - let(:application) { create(:clusters_applications_ingress, :installed) } - - before do - application.schedule_status_update - end - - it 'schedules a ClusterWaitForIngressIpAddressWorker' do - expect(ClusterWaitForIngressIpAddressWorker).to have_received(:perform_async) - .with('ingress', application.id) - end - - context 'when the application is not installed' do - let(:application) { create(:clusters_applications_ingress, :installing) } - - it 'does not schedule a ClusterWaitForIngressIpAddressWorker' do - expect(ClusterWaitForIngressIpAddressWorker).not_to have_received(:perform_async) - end - end - - context 'when there is already an external_ip' do - let(:application) { create(:clusters_applications_ingress, :installed, external_ip: '111.222.222.111') } - - it 'does not schedule a ClusterWaitForIngressIpAddressWorker' do - expect(ClusterWaitForIngressIpAddressWorker).not_to have_received(:perform_in) - end - end - - context 'when there is already an external_hostname' do - let(:application) { create(:clusters_applications_ingress, :installed, external_hostname: 'localhost.localdomain') } - - it 'does not schedule a ClusterWaitForIngressIpAddressWorker' do - expect(ClusterWaitForIngressIpAddressWorker).not_to have_received(:perform_in) - end - end - end - - describe '#install_command' do - subject { ingress.install_command } - - it { is_expected.to be_an_instance_of(Gitlab::Kubernetes::Helm::V3::InstallCommand) } - - it 'is initialized with ingress arguments' do - expect(subject.name).to eq('ingress') - expect(subject.chart).to eq('ingress/nginx-ingress') - expect(subject.version).to eq('1.40.2') - expect(subject).to be_rbac - expect(subject.files).to eq(ingress.files) - end - - context 'on a non rbac enabled cluster' do - before do - ingress.cluster.platform_kubernetes.abac! - end - - it { is_expected.not_to be_rbac } - end - - context 'application failed to install previously' do - let(:ingress) { create(:clusters_applications_ingress, :errored, version: 'nginx') } - - it 'is initialized with the locked version' do - expect(subject.version).to eq('1.40.2') - end - end - end - - describe '#files' do - let(:application) { ingress } - let(:values) { subject[:'values.yaml'] } - - subject { application.files } - - it 'includes ingress valid keys in values' do - expect(values).to include('image') - expect(values).to include('repository') - expect(values).to include('stats') - expect(values).to include('podAnnotations') - expect(values).to include('clusterIP') - end - end -end diff --git a/spec/models/clusters/cluster_spec.rb b/spec/models/clusters/cluster_spec.rb index 578b09740a5..f1d4a91f289 100644 --- a/spec/models/clusters/cluster_spec.rb +++ b/spec/models/clusters/cluster_spec.rb @@ -24,7 +24,6 @@ feature_category: :kubernetes_management do it { is_expected.to have_one(:platform_kubernetes) } it { is_expected.to have_one(:integration_prometheus) } it { is_expected.to have_one(:application_helm) } - it { is_expected.to have_one(:application_ingress) } it { is_expected.to have_many(:kubernetes_namespaces) } it { is_expected.to have_one(:cluster_project) } it { is_expected.to have_many(:deployment_clusters) } @@ -34,8 +33,6 @@ feature_category: :kubernetes_management do it { is_expected.to delegate_method(:status).to(:provider) } it { is_expected.to delegate_method(:status_reason).to(:provider) } - it { is_expected.to delegate_method(:external_ip).to(:application_ingress).with_prefix } - it { is_expected.to delegate_method(:external_hostname).to(:application_ingress).with_prefix } it { is_expected.to respond_to :project } it { is_expected.to be_namespace_per_environment } @@ -711,10 +708,9 @@ feature_category: :kubernetes_management do context 'when applications are created' do let!(:helm) { create(:clusters_applications_helm, cluster: cluster) } - let!(:ingress) { create(:clusters_applications_ingress, cluster: cluster) } it 'returns a list of created applications' do - is_expected.to contain_exactly(helm, ingress) + is_expected.to contain_exactly(helm) end end end @@ -1502,34 +1498,4 @@ feature_category: :kubernetes_management do end end end - - describe '#application_ingress_available?' do - subject(:application_ingress_available?) { cluster.application_ingress_available? } - - before do - allow(cluster).to receive(:application_ingress).and_return(application_ingress) - end - - context 'without application_ingress' do - let(:application_ingress) {} - - it { is_expected.to eq(false) } - end - - context 'with application_ingress' do - let(:application_ingress) { instance_double(Clusters::Applications::Ingress, available?: available?) } - - context 'with available? set to true' do - let(:available?) { true } - - it { is_expected.to eq(true) } - end - - context 'with available? set to false' do - let(:available?) { false } - - it { is_expected.to eq(false) } - end - end - end end diff --git a/spec/requests/api/lint_spec.rb b/spec/requests/api/lint_spec.rb index 3f131862a41..bc535e7e38a 100644 --- a/spec/requests/api/lint_spec.rb +++ b/spec/requests/api/lint_spec.rb @@ -4,168 +4,139 @@ require 'spec_helper' RSpec.describe API::Lint, feature_category: :pipeline_composition do describe 'POST /ci/lint' do - context 'when signup settings are disabled' do - before do - Gitlab::CurrentSettings.signup_enabled = false - end + it 'responds with a 410' do + user = create(:user) - context 'when unauthenticated' do - it 'returns authentication error' do - post api('/ci/lint'), params: { content: 'content' } + post api('/ci/lint', user), params: { content: "test_job:\n script: ls" } - expect(response).to have_gitlab_http_status(:unauthorized) - end - end - - context 'when authenticated' do - let_it_be(:api_user) { create(:user) } - - it 'returns authorized' do - post api('/ci/lint', api_user), params: { content: 'content' } + expect(response).to have_gitlab_http_status(:gone) + end - expect(response).to have_gitlab_http_status(:ok) - end + context 'when ci_remove_post_lint is disabled' do + before do + stub_feature_flags(ci_remove_post_lint: false) end - context 'when authenticated as external user' do - let(:project) { create(:project) } - let(:api_user) { create(:user, :external) } - - context 'when reporter in a project' do - before do - project.add_reporter(api_user) - end + context 'when signup settings are disabled' do + before do + Gitlab::CurrentSettings.signup_enabled = false + end - it 'returns authorization failure' do - post api('/ci/lint', api_user), params: { content: 'content' } + context 'when unauthenticated' do + it 'returns authentication error' do + post api('/ci/lint'), params: { content: 'content' } expect(response).to have_gitlab_http_status(:unauthorized) end end - context 'when developer in a project' do - before do - project.add_developer(api_user) - end + context 'when authenticated' do + let_it_be(:api_user) { create(:user) } - it 'returns authorization success' do + it 'returns authorized' do post api('/ci/lint', api_user), params: { content: 'content' } expect(response).to have_gitlab_http_status(:ok) end end - end - end - context 'when signup is enabled and not limited' do - before do - Gitlab::CurrentSettings.signup_enabled = true - stub_application_setting(domain_allowlist: [], email_restrictions_enabled: false, require_admin_approval_after_user_signup: false) - end + context 'when authenticated as external user' do + let(:project) { create(:project) } + let(:api_user) { create(:user, :external) } - context 'when unauthenticated' do - it 'returns authorized success' do - post api('/ci/lint'), params: { content: 'content' } + context 'when reporter in a project' do + before do + project.add_reporter(api_user) + end - expect(response).to have_gitlab_http_status(:ok) - end - end + it 'returns authorization failure' do + post api('/ci/lint', api_user), params: { content: 'content' } - context 'when authenticated' do - let_it_be(:api_user) { create(:user) } + expect(response).to have_gitlab_http_status(:unauthorized) + end + end - it 'returns authentication success' do - post api('/ci/lint', api_user), params: { content: 'content' } + context 'when developer in a project' do + before do + project.add_developer(api_user) + end - expect(response).to have_gitlab_http_status(:ok) + it 'returns authorization success' do + post api('/ci/lint', api_user), params: { content: 'content' } + + expect(response).to have_gitlab_http_status(:ok) + end + end end end - end - context 'when limited signup is enabled' do - before do - stub_application_setting(domain_allowlist: ['www.gitlab.com']) - Gitlab::CurrentSettings.signup_enabled = true - end + context 'when signup is enabled and not limited' do + before do + Gitlab::CurrentSettings.signup_enabled = true + stub_application_setting(domain_allowlist: [], email_restrictions_enabled: false, require_admin_approval_after_user_signup: false) + end - context 'when unauthenticated' do - it 'returns unauthorized' do - post api('/ci/lint'), params: { content: 'content' } + context 'when unauthenticated' do + it 'returns authorized success' do + post api('/ci/lint'), params: { content: 'content' } - expect(response).to have_gitlab_http_status(:unauthorized) + expect(response).to have_gitlab_http_status(:ok) + end end - end - context 'when authenticated' do - let_it_be(:api_user) { create(:user) } + context 'when authenticated' do + let_it_be(:api_user) { create(:user) } - it 'returns authentication success' do - post api('/ci/lint', api_user), params: { content: 'content' } + it 'returns authentication success' do + post api('/ci/lint', api_user), params: { content: 'content' } - expect(response).to have_gitlab_http_status(:ok) + expect(response).to have_gitlab_http_status(:ok) + end end end - end - context 'when authenticated' do - let_it_be(:api_user) { create(:user) } - - context 'with valid .gitlab-ci.yml content' do - let(:yaml_content) do - File.read(Rails.root.join('spec/support/gitlab_stubs/gitlab_ci.yml')) + context 'when limited signup is enabled' do + before do + stub_application_setting(domain_allowlist: ['www.gitlab.com']) + Gitlab::CurrentSettings.signup_enabled = true end - it 'passes validation without warnings or errors' do - post api('/ci/lint', api_user), params: { content: yaml_content } + context 'when unauthenticated' do + it 'returns unauthorized' do + post api('/ci/lint'), params: { content: 'content' } - expect(response).to have_gitlab_http_status(:ok) - expect(json_response).to be_an Hash - expect(json_response['status']).to eq('valid') - expect(json_response['warnings']).to match_array([]) - expect(json_response['errors']).to match_array([]) - expect(json_response['includes']).to eq([]) + expect(response).to have_gitlab_http_status(:unauthorized) + end end - it 'outputs expanded yaml content' do - post api('/ci/lint', api_user), params: { content: yaml_content, include_merged_yaml: true } - - expect(response).to have_gitlab_http_status(:ok) - expect(json_response).to have_key('merged_yaml') - end + context 'when authenticated' do + let_it_be(:api_user) { create(:user) } - it 'outputs jobs' do - post api('/ci/lint', api_user), params: { content: yaml_content, include_jobs: true } + it 'returns authentication success' do + post api('/ci/lint', api_user), params: { content: 'content' } - expect(response).to have_gitlab_http_status(:ok) - expect(json_response).to have_key('jobs') + expect(response).to have_gitlab_http_status(:ok) + end end end - context 'with valid .gitlab-ci.yml with warnings' do - let(:yaml_content) { { job: { script: 'ls', rules: [{ when: 'always' }] } }.to_yaml } - - it 'passes validation but returns warnings' do - post api('/ci/lint', api_user), params: { content: yaml_content } - - expect(response).to have_gitlab_http_status(:ok) - expect(json_response['status']).to eq('valid') - expect(json_response['warnings']).not_to be_empty - expect(json_response['errors']).to match_array([]) - end - end + context 'when authenticated' do + let_it_be(:api_user) { create(:user) } - context 'with an invalid .gitlab-ci.yml' do - context 'with invalid syntax' do - let(:yaml_content) { 'invalid content' } + context 'with valid .gitlab-ci.yml content' do + let(:yaml_content) do + File.read(Rails.root.join('spec/support/gitlab_stubs/gitlab_ci.yml')) + end - it 'responds with errors about invalid syntax' do + it 'passes validation without warnings or errors' do post api('/ci/lint', api_user), params: { content: yaml_content } expect(response).to have_gitlab_http_status(:ok) - expect(json_response['status']).to eq('invalid') - expect(json_response['warnings']).to eq([]) - expect(json_response['errors']).to eq(['Invalid configuration format']) - expect(json_response['includes']).to eq(nil) + expect(json_response).to be_an Hash + expect(json_response['status']).to eq('valid') + expect(json_response['warnings']).to match_array([]) + expect(json_response['errors']).to match_array([]) + expect(json_response['includes']).to eq([]) end it 'outputs expanded yaml content' do @@ -183,41 +154,84 @@ RSpec.describe API::Lint, feature_category: :pipeline_composition do end end - context 'with invalid configuration' do - let(:yaml_content) { '{ image: "image:1.0", services: ["postgres"] }' } + context 'with valid .gitlab-ci.yml with warnings' do + let(:yaml_content) { { job: { script: 'ls', rules: [{ when: 'always' }] } }.to_yaml } - it 'responds with errors about invalid configuration' do + it 'passes validation but returns warnings' do post api('/ci/lint', api_user), params: { content: yaml_content } expect(response).to have_gitlab_http_status(:ok) - expect(json_response['status']).to eq('invalid') - expect(json_response['warnings']).to eq([]) - expect(json_response['errors']).to eq(['jobs config should contain at least one visible job']) - expect(json_response['includes']).to eq([]) + expect(json_response['status']).to eq('valid') + expect(json_response['warnings']).not_to be_empty + expect(json_response['errors']).to match_array([]) end + end - it 'outputs expanded yaml content' do - post api('/ci/lint', api_user), params: { content: yaml_content, include_merged_yaml: true } + context 'with an invalid .gitlab-ci.yml' do + context 'with invalid syntax' do + let(:yaml_content) { 'invalid content' } - expect(response).to have_gitlab_http_status(:ok) - expect(json_response).to have_key('merged_yaml') + it 'responds with errors about invalid syntax' do + post api('/ci/lint', api_user), params: { content: yaml_content } + + expect(response).to have_gitlab_http_status(:ok) + expect(json_response['status']).to eq('invalid') + expect(json_response['warnings']).to eq([]) + expect(json_response['errors']).to eq(['Invalid configuration format']) + expect(json_response['includes']).to eq(nil) + end + + it 'outputs expanded yaml content' do + post api('/ci/lint', api_user), params: { content: yaml_content, include_merged_yaml: true } + + expect(response).to have_gitlab_http_status(:ok) + expect(json_response).to have_key('merged_yaml') + end + + it 'outputs jobs' do + post api('/ci/lint', api_user), params: { content: yaml_content, include_jobs: true } + + expect(response).to have_gitlab_http_status(:ok) + expect(json_response).to have_key('jobs') + end end - it 'outputs jobs' do - post api('/ci/lint', api_user), params: { content: yaml_content, include_jobs: true } + context 'with invalid configuration' do + let(:yaml_content) { '{ image: "image:1.0", services: ["postgres"] }' } - expect(response).to have_gitlab_http_status(:ok) - expect(json_response).to have_key('jobs') + it 'responds with errors about invalid configuration' do + post api('/ci/lint', api_user), params: { content: yaml_content } + + expect(response).to have_gitlab_http_status(:ok) + expect(json_response['status']).to eq('invalid') + expect(json_response['warnings']).to eq([]) + expect(json_response['errors']).to eq(['jobs config should contain at least one visible job']) + expect(json_response['includes']).to eq([]) + end + + it 'outputs expanded yaml content' do + post api('/ci/lint', api_user), params: { content: yaml_content, include_merged_yaml: true } + + expect(response).to have_gitlab_http_status(:ok) + expect(json_response).to have_key('merged_yaml') + end + + it 'outputs jobs' do + post api('/ci/lint', api_user), params: { content: yaml_content, include_jobs: true } + + expect(response).to have_gitlab_http_status(:ok) + expect(json_response).to have_key('jobs') + end end end - end - context 'without the content parameter' do - it 'responds with validation error about missing content' do - post api('/ci/lint', api_user) + context 'without the content parameter' do + it 'responds with validation error about missing content' do + post api('/ci/lint', api_user) - expect(response).to have_gitlab_http_status(:bad_request) - expect(json_response['error']).to eq('content is missing') + expect(response).to have_gitlab_http_status(:bad_request) + expect(json_response['error']).to eq('content is missing') + end end end end diff --git a/spec/requests/api/protected_branches_spec.rb b/spec/requests/api/protected_branches_spec.rb index 463893afd13..622e57edf6a 100644 --- a/spec/requests/api/protected_branches_spec.rb +++ b/spec/requests/api/protected_branches_spec.rb @@ -5,6 +5,7 @@ require 'spec_helper' RSpec.describe API::ProtectedBranches, feature_category: :source_code_management do let_it_be_with_reload(:project) { create(:project, :repository) } let_it_be(:maintainer) { create(:user) } + let_it_be(:developer) { create(:user) } let_it_be(:guest) { create(:user) } let(:protected_name) { 'feature' } @@ -16,12 +17,14 @@ RSpec.describe API::ProtectedBranches, feature_category: :source_code_management before_all do project.add_maintainer(maintainer) + project.add_developer(developer) project.add_guest(guest) end describe "GET /projects/:id/protected_branches" do let(:params) { {} } let(:route) { "/projects/#{project.id}/protected_branches" } + let(:expected_branch_names) { project.protected_branches.map { |x| x['name'] } } shared_examples_for 'protected branches' do it 'returns the protected branches' do @@ -39,9 +42,7 @@ RSpec.describe API::ProtectedBranches, feature_category: :source_code_management let(:user) { maintainer } context 'when search param is not present' do - it_behaves_like 'protected branches' do - let(:expected_branch_names) { project.protected_branches.map { |x| x['name'] } } - end + it_behaves_like 'protected branches' end context 'when search param is present' do @@ -53,6 +54,12 @@ RSpec.describe API::ProtectedBranches, feature_category: :source_code_management end end + context 'when authenticated as a developer' do + let(:user) { developer } + + it_behaves_like 'protected branches' + end + context 'when authenticated as a guest' do let(:user) { guest } @@ -105,6 +112,12 @@ RSpec.describe API::ProtectedBranches, feature_category: :source_code_management end end + context 'when authenticated as a developer' do + let(:user) { developer } + + it_behaves_like 'protected branch' + end + context 'when authenticated as a guest' do let(:user) { guest } @@ -243,10 +256,20 @@ RSpec.describe API::ProtectedBranches, feature_category: :source_code_management end end + context 'when authenticated as a developer' do + let(:user) { developer } + + it "returns a 403 error" do + post post_endpoint, params: { name: branch_name } + + expect(response).to have_gitlab_http_status(:forbidden) + end + end + context 'when authenticated as a guest' do let(:user) { guest } - it "returns a 403 error if guest" do + it "returns a 403 error" do post post_endpoint, params: { name: branch_name } expect(response).to have_gitlab_http_status(:forbidden) @@ -295,6 +318,16 @@ RSpec.describe API::ProtectedBranches, feature_category: :source_code_management end end + context 'when authenticated as a developer' do + let(:user) { developer } + + it "returns a 403 error" do + patch api(route, user), params: { allow_force_push: true } + + expect(response).to have_gitlab_http_status(:forbidden) + end + end + context 'when authenticated as a guest' do let(:user) { guest } @@ -307,42 +340,65 @@ RSpec.describe API::ProtectedBranches, feature_category: :source_code_management end describe "DELETE /projects/:id/protected_branches/unprotect/:branch" do - let(:user) { maintainer } let(:delete_endpoint) { api("/projects/#{project.id}/protected_branches/#{branch_name}", user) } - it "unprotects a single branch" do - delete delete_endpoint + context "when authenticated as a maintainer" do + let(:user) { maintainer } + + it "unprotects a single branch" do + delete delete_endpoint - expect(response).to have_gitlab_http_status(:no_content) - end + expect(response).to have_gitlab_http_status(:no_content) + end - it_behaves_like '412 response' do - let(:request) { delete_endpoint } - end + it_behaves_like '412 response' do + let(:request) { delete_endpoint } + end - it "returns 404 if branch does not exist" do - delete api("/projects/#{project.id}/protected_branches/barfoo", user) + it "returns 404 if branch does not exist" do + delete api("/projects/#{project.id}/protected_branches/barfoo", user) - expect(response).to have_gitlab_http_status(:not_found) + expect(response).to have_gitlab_http_status(:not_found) + end + + context 'when a policy restricts rule deletion' do + it "prevents deletion of the protected branch rule" do + disallow(:destroy_protected_branch, protected_branch) + + delete delete_endpoint + + expect(response).to have_gitlab_http_status(:forbidden) + end + end + + context 'when branch has a wildcard in its name' do + let(:protected_name) { 'feature*' } + + it "unprotects a wildcard branch" do + delete delete_endpoint + + expect(response).to have_gitlab_http_status(:no_content) + end + end end - context 'when a policy restricts rule deletion' do - it "prevents deletion of the protected branch rule" do - disallow(:destroy_protected_branch, protected_branch) + context 'when authenticated as a developer' do + let(:user) { developer } + it "returns a 403 error" do delete delete_endpoint expect(response).to have_gitlab_http_status(:forbidden) end end - context 'when branch has a wildcard in its name' do - let(:protected_name) { 'feature*' } + context 'when authenticated as a guest' do + let(:user) { guest } - it "unprotects a wildcard branch" do + it "returns a 403 error" do delete delete_endpoint - expect(response).to have_gitlab_http_status(:no_content) + expect(response).to have_gitlab_http_status(:forbidden) end end end |