diff --git a/qa/qa/specs/features/browser_ui/10_govern/login/register_spec.rb b/qa/qa/specs/features/browser_ui/10_govern/login/register_spec.rb index e478975507abb115e7e33b297fd0a256ff645e67..96f9bf87f3ad90f50bf9065370ff10928cd21361 100644 --- a/qa/qa/specs/features/browser_ui/10_govern/login/register_spec.rb +++ b/qa/qa/specs/features/browser_ui/10_govern/login/register_spec.rb @@ -1,21 +1,21 @@ # frozen_string_literal: true module QA - RSpec.shared_examples 'registration and login' do - it 'allows the user to register and login' do - Runtime::Browser.visit(:gitlab, Page::Main::Login) + RSpec.describe 'Govern', :skip_signup_disabled, :requires_admin, product_group: :authentication do + shared_examples 'registration and login' do + it 'allows the user to register and login' do + Runtime::Browser.visit(:gitlab, Page::Main::Login) - Resource::User.fabricate_via_browser_ui! do |user_resource| - user_resource.email_domain = 'gitlab.com' - end + Resource::User.fabricate_via_browser_ui! do |user_resource| + user_resource.email_domain = 'gitlab.com' + end - Page::Main::Menu.perform do |menu| - expect(menu).to have_personal_area + Page::Main::Menu.perform do |menu| + expect(menu).to have_personal_area + end end end - end - RSpec.describe 'Govern', :skip_signup_disabled, :requires_admin, product_group: :authentication do describe 'while LDAP is enabled', :blocking, :orchestrated, :ldap_no_tls, testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347934' do let!(:personal_access_token) { Runtime::Env.personal_access_token } @@ -43,33 +43,24 @@ module QA it_behaves_like 'registration and login' end - describe 'standard', :smoke, :external_api_calls, - testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347867' do + # TODO: needs to be refactored to correctly support parallel testing + # If any other spec file depends on require_admin_approval setting, it could fail + describe 'standard', :smoke, :external_api_calls do context 'when admin approval is not required' do - before(:all) do - set_require_admin_approval_after_user_signup(false) + around do |example| + with_application_settings(require_admin_approval_after_user_signup: false) { example.run } end - it_behaves_like 'registration and login' + context "with basic registration", + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347867' do + it_behaves_like 'registration and login' + end - context 'when user account is deleted' do - let(:admin_api_client) { Runtime::API::Client.as_admin } - let(:name) { "FirstName Last#{SecureRandom.hex(6)}" } - let(:email) { "email_#{SecureRandom.hex(6)}@example.com" } - let(:username) { "username_#{SecureRandom.hex(6)}" } - let(:user) { create(:user, api_client: admin_api_client, name: name, email: email, username: username) } - let(:recreated_user) do - Resource::User.fabricate_via_browser_ui! do |resource| - resource.name = name - resource.username = username - resource.email = email - end - end + context "with user deletion" do + let(:user) { create(:user) } - before do - # Use the UI instead of API to delete the account since - # this is the only test that exercise this UI. - # Other tests should use the API for this purpose. + it "allows to delete user account", + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/500258' do Flow::Login.sign_in(as: user) Page::Main::Menu.perform(&:click_edit_profile_link) Page::Profile::Menu.perform(&:click_account) @@ -77,20 +68,25 @@ module QA show.delete_account(user.password) end - Support::Waiter.wait_until(max_duration: 120, sleep_interval: 3) { !user.exists? } + expect { user.exists? }.to eventually_be_falsey.within(max_duration: 120, sleep_interval: 3), + "Expected user to be deleted, but it still exists" end - it 'allows recreating with same credentials', :blocking, :external_api_calls, - testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347868' do - expect(Page::Main::Menu.perform(&:signed_in?)).to be_falsy + it "allows to recreate deleted user with same credeintials", + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/500257' do + user.remove_via_api! + # make sure user is deleted + Support::Waiter.wait_until(max_duration: 120, sleep_interval: 3) { !user.exists? } Flow::Login.sign_in(as: user, skip_page_validation: true) - expect(page).to have_text("Invalid login or password") - recreated_user - - expect(Page::Main::Menu.perform(&:signed_in?)).to be_truthy + Resource::User.fabricate_via_browser_ui! do |resource| + resource.name = user.name + resource.username = user.username + resource.email = user.email + end + expect(Page::Main::Menu.perform(&:signed_in?)).to be_truthy, "Expected user to be recreated successfully" end end end @@ -114,12 +110,8 @@ module QA end end - before do - set_require_admin_approval_after_user_signup(true) - end - - after do - set_require_admin_approval_after_user_signup(false) + around do |example| + with_application_settings(require_admin_approval_after_user_signup: true) { example.run } end it 'allows user login after approval' do @@ -165,17 +157,11 @@ def approve_user(user) end end - def set_require_admin_approval_after_user_signup(enable_or_disable) - return if get_require_admin_approval_after_user_signup == enable_or_disable - - Runtime::ApplicationSettings.set_application_settings(require_admin_approval_after_user_signup: enable_or_disable) - QA::Support::Retrier.retry_until(max_duration: 10, sleep_interval: 1) do - get_require_admin_approval_after_user_signup == enable_or_disable - end - end - - def get_require_admin_approval_after_user_signup - Runtime::ApplicationSettings.get_application_settings[:require_admin_approval_after_user_signup] + def with_application_settings(**hargs) + Runtime::ApplicationSettings.set_application_settings(**hargs) + yield + ensure + Runtime::ApplicationSettings.restore_application_settings(*hargs.keys) end end end diff --git a/qa/qa/specs/features/ee/browser_ui/3_create/repository/push_rules_spec.rb b/qa/qa/specs/features/ee/browser_ui/3_create/repository/push_rules_spec.rb index 78f5ded9e3e138e6171605ad5609094af47bab64..5c9d8b4821e1ba8289a0c91610b2317825c0d189 100644 --- a/qa/qa/specs/features/ee/browser_ui/3_create/repository/push_rules_spec.rb +++ b/qa/qa/specs/features/ee/browser_ui/3_create/repository/push_rules_spec.rb @@ -2,115 +2,138 @@ module QA RSpec.describe 'Create' do - describe 'Push rules', product_group: :source_code do - context 'using non signed commits' do - before(:context) do - prepare - - @file_name_limitation = 'denied_file' - @file_size_limitation = 1 - @authors_email_limitation = %{(#{Regexp.escape(@creator.email)}|#{@root.email})} - @branch_name_limitation = @project.default_branch - @needed_phrase_limitation = 'allowed commit' - @deny_message_phrase_limitation = 'denied commit' + describe 'Push rules', :requires_admin, product_group: :source_code do + let!(:creator) { create(:user, username: Runtime::User.username, password: Runtime::User.password) } + + let!(:project) do + create( + :project, + name: 'push_rules', + initialize_with_readme: true, + api_client: Runtime::API::Client.new(user: creator)) + end - Page::Project::Settings::Repository.perform do |repository| - repository.expand_push_rules do |push_rules| - push_rules.fill_file_name(@file_name_limitation) - push_rules.fill_file_size(@file_size_limitation) - push_rules.fill_author_email(@authors_email_limitation) - push_rules.fill_branch_name(@branch_name_limitation) - push_rules.fill_commit_message_rule(@needed_phrase_limitation) - push_rules.fill_deny_commit_message_rule(@deny_message_phrase_limitation) - push_rules.check_prevent_secrets - push_rules.check_deny_delete_tag - push_rules.click_submit - end + let(:root) { build(:user, username: 'root', name: 'GitLab QA', email: 'root@gitlab.com', password: nil) } + let(:file_name_limitation) { 'denied_file' } + let(:file_size_limitation) { 1 } + let(:branch_name_limitation) { project.default_branch } + let(:needed_phrase_limitation) { 'allowed commit' } + let(:deny_message_phrase_limitation) { 'denied commit' } + + before do + Flow::Login.sign_in(as: creator) + project.visit! + + Page::Project::Menu.perform(&:go_to_repository_settings) + # TODO: implement push rules api support to remove rule setup via UI - https://docs.gitlab.com/ee/api/project_push_rules.html + Page::Project::Settings::Repository.perform do |repository| + repository.expand_push_rules do |push_rules| + push_rules.fill_file_name(file_name_limitation) + push_rules.fill_file_size(file_size_limitation) + push_rules.fill_branch_name(branch_name_limitation) + push_rules.fill_commit_message_rule(needed_phrase_limitation) + push_rules.fill_deny_commit_message_rule(deny_message_phrase_limitation) + push_rules.check_prevent_secrets + push_rules.check_deny_delete_tag + push_rules.click_submit end end + end - it 'allows an unrestricted push', :blocking, testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347790' do + context 'when using non signed commits' do + it 'allows an unrestricted push', :blocking, + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347790' do expect_no_error_on_push(file: standard_file) end - it 'restricts files by name and size', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347784', quarantine: { - only: { job: 'ee-qa-browser_ui-3_create' }, - type: :investigating, - issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/455927' - } do - # Note: The file size limits in this test should be lower than the limits in - # browser_ui/3_create/repository/push_over_http_file_size_spec to prevent - # the limit set in that test from triggering in this test (which can happen - # on Staging where the tests are run in parallel). - # See: https://gitlab.com/gitlab-org/gitlab/-/issues/218620#note_361634705 - - large_file = [{ - name: 'file', - content: SecureRandom.hex(1000000) - }] - wrongly_named_file = [{ - name: @file_name_limitation, - content: SecureRandom.hex(100) - }] - + it 'restricts files by name and size', + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347784' do expect_error_on_push( - file: large_file, + file: { + name: 'file', + content: SecureRandom.hex(1000000) + }, error: 'File "file" is larger than the allowed size of 1 MiB') expect_error_on_push( - file: wrongly_named_file, - error: Regexp.escape(%(File name #{@file_name_limitation} was prohibited by the pattern "#{@file_name_limitation}"))) - end + file: { + name: file_name_limitation, + content: SecureRandom.hex(100) + }, + error: Regexp.escape( + %(File name #{file_name_limitation} was prohibited by the pattern "#{file_name_limitation}") + ) + ) + end + + it 'restricts users by email format', :blocking, + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347783' do + authors_email_limitation = %{(#{Regexp.escape(creator.email)}|#{root.email})} + gitlab_user = create(:user) + project.add_member(gitlab_user, Resource::Members::AccessLevel::MAINTAINER) - it 'restricts users by email format', :blocking, testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347783' do - gitlab_user = Resource::User.fabricate_or_use(Runtime::Env.gitlab_qa_username_2, Runtime::Env.gitlab_qa_password_2) - @project.add_member(gitlab_user, Resource::Members::AccessLevel::MAINTAINER) + Page::Project::Settings::Repository.perform do |repository| + repository.expand_push_rules do |push_rules| + push_rules.fill_author_email(authors_email_limitation) + push_rules.click_submit + end + end expect_error_on_push( file: standard_file, user: gitlab_user, - error: Regexp.escape("Committer's email '#{gitlab_user.email}' does not follow the pattern '#{@authors_email_limitation}'")) + error: Regexp.escape( + "Committer's email '#{gitlab_user.email}' does not follow the pattern '#{authors_email_limitation}'" + ) + ) end - it 'restricts branches by branch name', :blocking, testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347781' do + it 'restricts branches by branch name', :blocking, + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347781' do expect_error_on_push( file: standard_file, branch: 'forbidden_branch', - error: Regexp.escape("Branch name 'forbidden_branch' does not follow the pattern '#{@branch_name_limitation}'")) + error: Regexp.escape( + "Branch name 'forbidden_branch' does not follow the pattern '#{branch_name_limitation}'") + ) end - it 'restricts commit by message format', :blocking, testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347780' do - expect_no_error_on_push(file: standard_file, commit_message: @needed_phrase_limitation) + it 'restricts commit by message format', :blocking, + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347780' do + expect_no_error_on_push(file: standard_file, commit_message: needed_phrase_limitation) expect_error_on_push( file: standard_file, commit_message: 'forbidden message', - error: Regexp.escape("Commit message does not follow the pattern '#{@needed_phrase_limitation}'")) + error: Regexp.escape("Commit message does not follow the pattern '#{needed_phrase_limitation}'")) expect_error_on_push( file: standard_file, - commit_message: "#{@needed_phrase_limitation} - #{@deny_message_phrase_limitation}", - error: Regexp.escape("Commit message contains the forbidden pattern '#{@deny_message_phrase_limitation}'")) + commit_message: "#{needed_phrase_limitation} - #{deny_message_phrase_limitation}", + error: Regexp.escape("Commit message contains the forbidden pattern '#{deny_message_phrase_limitation}'")) end - it 'restricts committing files with secrets', :blocking, testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347779' do - secret_file = [{ - name: 'id_rsa', - content: SecureRandom.hex(100) - }] - + it 'restricts committing files with secrets', :blocking, + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347779' do expect_error_on_push( - file: secret_file, + file: { + name: 'id_rsa', + content: SecureRandom.hex(100) + }, error: Regexp.escape('File name id_rsa was prohibited by the pattern "id_rsa$"')) end - it 'restricts removal of tag', :blocking, testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347782' do - tag = create(:tag, project: @project, ref: @project.default_branch, name: "test_tag_#{SecureRandom.hex(8)}") + it 'restricts removal of tag', :blocking, + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347782' do + tag = create(:tag, project: project, ref: project.default_branch, name: "test_tag") expect_error_on_push(file: standard_file, tag: tag.name, error: 'You cannot delete a tag') end - end - context 'with commits restricted by author email to existing GitLab users' do - before do - prepare + it 'restricts non-member users', :blocking, + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347812' do + non_member_user = build(:user, + username: creator.username, + password: creator.password, + name: 'non_member_user', + email: 'non_member_user@non_member_user.com') Page::Project::Settings::Repository.perform do |repository| repository.expand_push_rules do |push_rules| @@ -118,114 +141,110 @@ module QA push_rules.click_submit end end - end - - it 'rejects non-member users', :blocking, testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347812' do - non_member_user = build(:user, - username: '', - password: '', - name: 'non_member_user', - email: 'non_member_user@non_member_user.com') expect_error_on_push( file: standard_file, user: non_member_user, error: Regexp.escape("Author '#{non_member_user.email}' is not a member of team")) end - end - - context 'with commits restricted to verified emails' do - before do - prepare + it 'restricts unverified emails', :blocking, + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347791' do Page::Project::Settings::Repository.perform do |repository| repository.expand_push_rules do |push_rules| push_rules.check_committer_restriction push_rules.click_submit end end - end - it 'rejects unverified emails', :blocking, testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347791' do expect_no_error_on_push(file: standard_file) expect_error_on_push( file: standard_file, - user: @root, + user: root, error: 'You can only push commits if the committer email is one of your own verified emails') end end - context 'using signed commits' do - before do - prepare + context 'when using signed commits' do + let(:gpg) { Resource::UserGPG.fabricate_via_api! } + before do Page::Project::Settings::Repository.perform do |repository| repository.expand_push_rules do |push_rules| push_rules.check_reject_unsigned_commits push_rules.click_submit end end - - @gpg = Resource::UserGPG.fabricate_via_api! end - it 'restricts to signed commits', :blocking, testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347785' do - expect_no_error_on_push(file: standard_file, gpg: @gpg) + it 'restricts to signed commits', :blocking, + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347785' do + expect_no_error_on_push(file: standard_file, gpg: gpg) expect_error_on_push(file: standard_file, error: 'Commit must be signed with a GPG key') end end def standard_file - [{ + { name: 'file', content: SecureRandom.hex(100) - }] + } end def push(commit_message:, branch:, file:, user:, tag:, gpg:, max_attempts:) Resource::Repository::ProjectPush.fabricate! do |push| - push.project = @project + push.project = project push.commit_message = commit_message - push.new_branch = branch != @project.default_branch + push.new_branch = branch != project.default_branch push.branch_name = branch - push.user = user if user != @root - push.files = file if tag.nil? + push.user = user if user != root + push.files = [file] if tag.nil? push.tag_name = tag unless tag.nil? push.gpg_key_id = gpg.key_id unless gpg.nil? push.max_attempts = max_attempts if max_attempts end end - def expect_no_error_on_push(file:, commit_message: 'allowed commit', branch: @project.default_branch, user: @creator, tag: nil, gpg: nil) + def expect_no_error_on_push( + file:, + commit_message: 'allowed commit', + branch: project.default_branch, + user: creator, + tag: nil, + gpg: nil + ) expect do - push commit_message: commit_message, branch: branch, file: file, user: user, tag: tag, gpg: gpg, max_attempts: 3 + push( + commit_message: commit_message, + branch: branch, + file: file, + user: user, + tag: tag, + gpg: gpg, + max_attempts: 3) end.not_to raise_error end - def expect_error_on_push(file:, commit_message: 'allowed commit', branch: @project.default_branch, user: @creator, tag: nil, gpg: nil, error: nil) + def expect_error_on_push( + file:, + commit_message: 'allowed commit', + branch: project.default_branch, + user: creator, + tag: nil, + gpg: nil, + error: nil + ) expect do - push commit_message: commit_message, branch: branch, file: file, user: user, tag: tag, gpg: gpg, max_attempts: 1 + push( + commit_message: commit_message, + branch: branch, + file: file, + user: user, + tag: tag, + gpg: gpg, + max_attempts: 1) end.to raise_error(QA::Support::Run::CommandError, /#{error}/) end - - def prepare - Flow::Login.sign_in - - @creator = create(:user, username: Runtime::User.username, password: Runtime::User.password) - - @root = build(:user, username: 'root', name: 'GitLab QA', email: 'root@gitlab.com', password: nil) - - @project = create(:project, name: 'push_rules') - - Resource::Repository::ProjectPush.fabricate! do |push| - push.project = @project - push.files = standard_file - end - - @project.visit! - - Page::Project::Menu.perform(&:go_to_repository_settings) - end end end end