diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-11-16 15:10:23 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-11-16 15:10:23 +0300 |
commit | dc9ff5fda1337883acd09fd4b98be2f6a41ad037 (patch) | |
tree | 0c720bccd583ddfb7ae355b81459d8e2ecde8ae8 /spec | |
parent | 2c90b9b579fbfe3db191a032d2cb176761605a02 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r-- | spec/controllers/projects/releases_controller_spec.rb | 13 | ||||
-rw-r--r-- | spec/db/schema_spec.rb | 1 | ||||
-rw-r--r-- | spec/factories/ci/reports/security/findings.rb | 4 | ||||
-rw-r--r-- | spec/features/cycle_analytics_spec.rb | 4 | ||||
-rw-r--r-- | spec/features/projects/releases/user_views_releases_spec.rb | 4 | ||||
-rw-r--r-- | spec/graphql/types/release_links_type_spec.rb | 44 | ||||
-rw-r--r-- | spec/lib/gitlab/analytics/cycle_analytics/aggregated/records_fetcher_spec.rb | 130 | ||||
-rw-r--r-- | spec/models/u2f_registration_spec.rb | 28 | ||||
-rw-r--r-- | spec/models/webauthn_registration_spec.rb | 23 | ||||
-rw-r--r-- | spec/presenters/release_presenter_spec.rb | 14 | ||||
-rw-r--r-- | spec/requests/api/graphql/project/release_spec.rb | 186 | ||||
-rw-r--r-- | spec/requests/api/graphql/project/releases_spec.rb | 15 | ||||
-rw-r--r-- | spec/services/packages/npm/create_package_service_spec.rb | 17 | ||||
-rw-r--r-- | spec/support/shared_examples/models/concerns/analytics/cycle_analytics/stage_event_model_examples.rb | 2 |
14 files changed, 455 insertions, 30 deletions
diff --git a/spec/controllers/projects/releases_controller_spec.rb b/spec/controllers/projects/releases_controller_spec.rb index a1e36ec5c4c..120020273f9 100644 --- a/spec/controllers/projects/releases_controller_spec.rb +++ b/spec/controllers/projects/releases_controller_spec.rb @@ -207,7 +207,18 @@ RSpec.describe Projects::ReleasesController do let(:project) { private_project } let(:user) { guest } - it_behaves_like 'not found' + it_behaves_like 'successful request' + end + + context 'when user is an external user for the project' do + let(:project) { private_project } + let(:user) { create(:user) } + + it 'behaves like not found' do + subject + + expect(response).to have_gitlab_http_status(:not_found) + end end end diff --git a/spec/db/schema_spec.rb b/spec/db/schema_spec.rb index 7785233875c..aebe13c39fe 100644 --- a/spec/db/schema_spec.rb +++ b/spec/db/schema_spec.rb @@ -29,6 +29,7 @@ RSpec.describe 'Database schema' do ci_builds: %w[erased_by_id runner_id trigger_request_id user_id], ci_namespace_monthly_usages: %w[namespace_id], ci_pipelines: %w[user_id], + ci_pipeline_chat_data: %w[chat_name_id], # it uses the loose foreign key featue ci_runner_projects: %w[runner_id], ci_trigger_requests: %w[commit_id], cluster_providers_aws: %w[security_group_id vpc_id access_key_id], diff --git a/spec/factories/ci/reports/security/findings.rb b/spec/factories/ci/reports/security/findings.rb index e3971bc48f3..8a39fce971f 100644 --- a/spec/factories/ci/reports/security/findings.rb +++ b/spec/factories/ci/reports/security/findings.rb @@ -9,7 +9,7 @@ FactoryBot.define do metadata_version { 'sast:1.0' } name { 'Cipher with no integrity' } report_type { :sast } - raw_metadata do + original_data do { description: "The cipher does not provide data integrity update 1", solution: "GCM mode introduces an HMAC into the resulting encrypted data, providing integrity of the result.", @@ -26,7 +26,7 @@ FactoryBot.define do url: "https://crypto.stackexchange.com/questions/31428/pbewithmd5anddes-cipher-does-not-check-for-integrity-first" } ] - }.to_json + }.deep_stringify_keys end scanner factory: :ci_reports_security_scanner severity { :high } diff --git a/spec/features/cycle_analytics_spec.rb b/spec/features/cycle_analytics_spec.rb index 0580e28512d..69361f66a71 100644 --- a/spec/features/cycle_analytics_spec.rb +++ b/spec/features/cycle_analytics_spec.rb @@ -34,6 +34,10 @@ RSpec.describe 'Value Stream Analytics', :js do wait_for_all_requests end + before do + stub_feature_flags(use_vsa_aggregated_tables: false) + end + context 'as an allowed user' do context 'when project is new' do before do diff --git a/spec/features/projects/releases/user_views_releases_spec.rb b/spec/features/projects/releases/user_views_releases_spec.rb index 6bc4c66b8ca..98935fdf872 100644 --- a/spec/features/projects/releases/user_views_releases_spec.rb +++ b/spec/features/projects/releases/user_views_releases_spec.rb @@ -123,11 +123,11 @@ RSpec.describe 'User views releases', :js do within('.release-block', match: :first) do expect(page).to have_content(release_v3.description) + expect(page).to have_content(release_v3.tag) + expect(page).to have_content(release_v3.name) # The following properties (sometimes) include Git info, # so they are not rendered for Guest users - expect(page).not_to have_content(release_v3.name) - expect(page).not_to have_content(release_v3.tag) expect(page).not_to have_content(release_v3.commit.short_id) end end diff --git a/spec/graphql/types/release_links_type_spec.rb b/spec/graphql/types/release_links_type_spec.rb index 38c38d58baa..e77c4e3ddd1 100644 --- a/spec/graphql/types/release_links_type_spec.rb +++ b/spec/graphql/types/release_links_type_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' RSpec.describe GitlabSchema.types['ReleaseLinks'] do - it { expect(described_class).to require_graphql_authorizations(:download_code) } + it { expect(described_class).to require_graphql_authorizations(:read_release) } it 'has the expected fields' do expected_fields = %w[ @@ -18,4 +18,46 @@ RSpec.describe GitlabSchema.types['ReleaseLinks'] do expect(described_class).to include_graphql_fields(*expected_fields) end + + context 'individual field authorization' do + def fetch_authorizations(field_name) + described_class.fields.dig(field_name).instance_variable_get(:@authorize) + end + + describe 'openedMergeRequestsUrl' do + it 'has valid authorization' do + expect(fetch_authorizations('openedMergeRequestsUrl')).to include(:download_code) + end + end + + describe 'mergedMergeRequestsUrl' do + it 'has valid authorization' do + expect(fetch_authorizations('mergedMergeRequestsUrl')).to include(:download_code) + end + end + + describe 'closedMergeRequestsUrl' do + it 'has valid authorization' do + expect(fetch_authorizations('closedMergeRequestsUrl')).to include(:download_code) + end + end + + describe 'openedIssuesUrl' do + it 'has valid authorization' do + expect(fetch_authorizations('openedIssuesUrl')).to include(:download_code) + end + end + + describe 'closedIssuesUrl' do + it 'has valid authorization' do + expect(fetch_authorizations('closedIssuesUrl')).to include(:download_code) + end + end + + describe 'editUrl' do + it 'has valid authorization' do + expect(fetch_authorizations('editUrl')).to include(:update_release) + end + end + end end diff --git a/spec/lib/gitlab/analytics/cycle_analytics/aggregated/records_fetcher_spec.rb b/spec/lib/gitlab/analytics/cycle_analytics/aggregated/records_fetcher_spec.rb new file mode 100644 index 00000000000..045cdb129cb --- /dev/null +++ b/spec/lib/gitlab/analytics/cycle_analytics/aggregated/records_fetcher_spec.rb @@ -0,0 +1,130 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::Analytics::CycleAnalytics::Aggregated::RecordsFetcher do + let_it_be(:project) { create(:project) } + let_it_be(:issue_1) { create(:issue, project: project) } + let_it_be(:issue_2) { create(:issue, project: project) } + let_it_be(:issue_3) { create(:issue, project: project) } + + let_it_be(:stage_event_1) { create(:cycle_analytics_issue_stage_event, issue_id: issue_1.id, start_event_timestamp: 2.years.ago, end_event_timestamp: 1.year.ago) } # duration: 1 year + let_it_be(:stage_event_2) { create(:cycle_analytics_issue_stage_event, issue_id: issue_2.id, start_event_timestamp: 5.years.ago, end_event_timestamp: 2.years.ago) } # duration: 3 years + let_it_be(:stage_event_3) { create(:cycle_analytics_issue_stage_event, issue_id: issue_3.id, start_event_timestamp: 6.years.ago, end_event_timestamp: 3.months.ago) } # duration: 5+ years + + let_it_be(:stage) { create(:cycle_analytics_project_stage, start_event_identifier: :issue_created, end_event_identifier: :issue_deployed_to_production, project: project) } + + let(:params) { {} } + + subject(:records_fetcher) do + described_class.new(stage: stage, query: Analytics::CycleAnalytics::IssueStageEvent.all, params: params) + end + + shared_examples 'match returned records' do + it 'returns issues in the correct order' do + returned_iids = records_fetcher.serialized_records.pluck(:iid).map(&:to_i) + + expect(returned_iids).to eq(expected_issue_ids) + end + end + + describe '#serialized_records' do + describe 'sorting' do + context 'when sorting by end event DESC' do + let(:expected_issue_ids) { [issue_3.iid, issue_1.iid, issue_2.iid] } + + before do + params[:sort] = :end_event + params[:direction] = :desc + end + + it_behaves_like 'match returned records' + end + + context 'when sorting by end event ASC' do + let(:expected_issue_ids) { [issue_2.iid, issue_1.iid, issue_3.iid] } + + before do + params[:sort] = :end_event + params[:direction] = :asc + end + + it_behaves_like 'match returned records' + end + + context 'when sorting by duration DESC' do + let(:expected_issue_ids) { [issue_3.iid, issue_2.iid, issue_1.iid] } + + before do + params[:sort] = :duration + params[:direction] = :desc + end + + it_behaves_like 'match returned records' + end + + context 'when sorting by duration ASC' do + let(:expected_issue_ids) { [issue_1.iid, issue_2.iid, issue_3.iid] } + + before do + params[:sort] = :duration + params[:direction] = :asc + end + + it_behaves_like 'match returned records' + end + end + + describe 'pagination' do + let(:expected_issue_ids) { [issue_3.iid] } + + before do + params[:sort] = :duration + params[:direction] = :asc + params[:page] = 2 + + stub_const('Gitlab::Analytics::CycleAnalytics::Aggregated::RecordsFetcher::MAX_RECORDS', 2) + end + + it_behaves_like 'match returned records' + end + + context 'when passing a block to serialized_records method' do + before do + params[:sort] = :duration + params[:direction] = :asc + end + + it 'yields the underlying stage event scope' do + stage_event_records = [] + + records_fetcher.serialized_records do |scope| + stage_event_records.concat(scope.to_a) + end + + expect(stage_event_records.map(&:issue_id)).to eq([issue_1.id, issue_2.id, issue_3.id]) + end + end + + context 'when the issue record no longer exists' do + it 'skips non-existing issue records' do + create(:cycle_analytics_issue_stage_event, { + issue_id: 0, # non-existing id + start_event_timestamp: 5.months.ago, + end_event_timestamp: 3.months.ago + }) + + stage_event_count = nil + + records_fetcher.serialized_records do |scope| + stage_event_count = scope.to_a.size + end + + issue_count = records_fetcher.serialized_records.to_a.size + + expect(stage_event_count).to eq(4) + expect(issue_count).to eq(3) + end + end + end +end diff --git a/spec/models/u2f_registration_spec.rb b/spec/models/u2f_registration_spec.rb index aba2f27d104..7a70cf69566 100644 --- a/spec/models/u2f_registration_spec.rb +++ b/spec/models/u2f_registration_spec.rb @@ -5,9 +5,11 @@ require 'spec_helper' RSpec.describe U2fRegistration do let_it_be(:user) { create(:user) } + let(:u2f_registration_name) { 'u2f_device' } + let(:u2f_registration) do device = U2F::FakeU2F.new(FFaker::BaconIpsum.characters(5)) - create(:u2f_registration, name: 'u2f_device', + create(:u2f_registration, name: u2f_registration_name, user: user, certificate: Base64.strict_encode64(device.cert_raw), key_handle: U2F.urlsafe_encode64(device.key_handle_raw), @@ -16,11 +18,27 @@ RSpec.describe U2fRegistration do describe 'callbacks' do describe '#create_webauthn_registration' do - it 'creates webauthn registration' do - u2f_registration.save! + shared_examples_for 'creates webauthn registration' do + it 'creates webauthn registration' do + u2f_registration.save! + + webauthn_registration = WebauthnRegistration.where(u2f_registration_id: u2f_registration.id) + expect(webauthn_registration).to exist + end + end + + it_behaves_like 'creates webauthn registration' + + context 'when the u2f_registration has a blank name' do + let(:u2f_registration_name) { '' } + + it_behaves_like 'creates webauthn registration' + end + + context 'when the u2f_registration has the name as `nil`' do + let(:u2f_registration_name) { nil } - webauthn_registration = WebauthnRegistration.where(u2f_registration_id: u2f_registration.id) - expect(webauthn_registration).to exist + it_behaves_like 'creates webauthn registration' end it 'logs error' do diff --git a/spec/models/webauthn_registration_spec.rb b/spec/models/webauthn_registration_spec.rb new file mode 100644 index 00000000000..6813854bf6c --- /dev/null +++ b/spec/models/webauthn_registration_spec.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe WebauthnRegistration do + describe 'relations' do + it { is_expected.to belong_to(:user) } + end + + describe 'validations' do + it { is_expected.to validate_presence_of(:credential_xid) } + it { is_expected.to validate_presence_of(:public_key) } + it { is_expected.to validate_presence_of(:counter) } + it { is_expected.to validate_length_of(:name).is_at_least(0) } + it { is_expected.not_to allow_value(nil).for(:name) } + it do + is_expected.to validate_numericality_of(:counter) + .only_integer + .is_greater_than_or_equal_to(0) + .is_less_than_or_equal_to(4294967295) + end + end +end diff --git a/spec/presenters/release_presenter_spec.rb b/spec/presenters/release_presenter_spec.rb index b2e7b684644..925a69ca92d 100644 --- a/spec/presenters/release_presenter_spec.rb +++ b/spec/presenters/release_presenter_spec.rb @@ -63,12 +63,6 @@ RSpec.describe ReleasePresenter do it 'returns its own url' do is_expected.to eq(project_release_url(project, release)) end - - context 'when user is guest' do - let(:user) { guest } - - it { is_expected.to be_nil } - end end describe '#opened_merge_requests_url' do @@ -147,13 +141,5 @@ RSpec.describe ReleasePresenter do it 'returns the release name' do is_expected.to eq release.name end - - context "when a user is not allowed to access any repository information" do - let(:presenter) { described_class.new(release, current_user: guest) } - - it 'returns a replacement name to avoid potentially leaking tag information' do - is_expected.to eq "Release-#{release.id}" - end - end end end diff --git a/spec/requests/api/graphql/project/release_spec.rb b/spec/requests/api/graphql/project/release_spec.rb index 7f24d051457..77abac4ef04 100644 --- a/spec/requests/api/graphql/project/release_spec.rb +++ b/spec/requests/api/graphql/project/release_spec.rb @@ -228,6 +228,189 @@ RSpec.describe 'Query.project(fullPath).release(tagName)' do end end + shared_examples 'restricted access to release fields' do + describe 'scalar fields' do + let(:path) { path_prefix } + + let(:release_fields) do + %{ + tagName + tagPath + description + descriptionHtml + name + createdAt + releasedAt + upcomingRelease + } + end + + before do + post_query + end + + it 'finds all release data' do + expect(data).to eq({ + 'tagName' => release.tag, + 'tagPath' => nil, + 'description' => release.description, + 'descriptionHtml' => release.description_html, + 'name' => release.name, + 'createdAt' => release.created_at.iso8601, + 'releasedAt' => release.released_at.iso8601, + 'upcomingRelease' => false + }) + end + end + + describe 'milestones' do + let(:path) { path_prefix + %w[milestones nodes] } + + let(:release_fields) do + query_graphql_field(:milestones, nil, 'nodes { id title }') + end + + it 'finds milestones associated to a release' do + post_query + + expected = release.milestones.order_by_dates_and_title.map do |milestone| + { 'id' => global_id_of(milestone), 'title' => milestone.title } + end + + expect(data).to eq(expected) + end + end + + describe 'author' do + let(:path) { path_prefix + %w[author] } + + let(:release_fields) do + query_graphql_field(:author, nil, 'id username') + end + + it 'finds the author of the release' do + post_query + + expect(data).to eq( + 'id' => global_id_of(release.author), + 'username' => release.author.username + ) + end + end + + describe 'commit' do + let(:path) { path_prefix + %w[commit] } + + let(:release_fields) do + query_graphql_field(:commit, nil, 'sha') + end + + it 'restricts commit associated with the release' do + post_query + + expect(data).to eq(nil) + end + end + + describe 'assets' do + describe 'count' do + let(:path) { path_prefix + %w[assets] } + + let(:release_fields) do + query_graphql_field(:assets, nil, 'count') + end + + it 'returns non source release links count' do + post_query + + expect(data).to eq('count' => release.assets_count(except: [:sources])) + end + end + + describe 'links' do + let(:path) { path_prefix + %w[assets links nodes] } + + let(:release_fields) do + query_graphql_field(:assets, nil, + query_graphql_field(:links, nil, 'nodes { id name url external, directAssetUrl }')) + end + + it 'finds all non source external release links' do + post_query + + expected = release.links.map do |link| + { + 'id' => global_id_of(link), + 'name' => link.name, + 'url' => link.url, + 'external' => true, + 'directAssetUrl' => link.filepath ? Gitlab::Routing.url_helpers.project_release_url(project, release) << "/downloads#{link.filepath}" : link.url + } + end + + expect(data).to match_array(expected) + end + end + + describe 'sources' do + let(:path) { path_prefix + %w[assets sources nodes] } + + let(:release_fields) do + query_graphql_field(:assets, nil, + query_graphql_field(:sources, nil, 'nodes { format url }')) + end + + it 'restricts release sources' do + post_query + + expect(data).to match_array([]) + end + end + end + + describe 'links' do + let(:path) { path_prefix + %w[links] } + + let(:release_fields) do + query_graphql_field(:links, nil, %{ + selfUrl + openedMergeRequestsUrl + mergedMergeRequestsUrl + closedMergeRequestsUrl + openedIssuesUrl + closedIssuesUrl + }) + end + + it 'finds only selfUrl' do + post_query + + expect(data).to eq( + 'selfUrl' => project_release_url(project, release), + 'openedMergeRequestsUrl' => nil, + 'mergedMergeRequestsUrl' => nil, + 'closedMergeRequestsUrl' => nil, + 'openedIssuesUrl' => nil, + 'closedIssuesUrl' => nil + ) + end + end + + describe 'evidences' do + let(:path) { path_prefix + %w[evidences] } + + let(:release_fields) do + query_graphql_field(:evidences, nil, 'nodes { id sha filepath collectedAt }') + end + + it 'restricts all evidence fields' do + post_query + + expect(data).to eq('nodes' => []) + end + end + end + shared_examples 'no access to the release field' do describe 'repository-related fields' do let(:path) { path_prefix } @@ -302,7 +485,8 @@ RSpec.describe 'Query.project(fullPath).release(tagName)' do context 'when the user has Guest permissions' do let(:current_user) { guest } - it_behaves_like 'no access to the release field' + it_behaves_like 'restricted access to release fields' + it_behaves_like 'no access to editUrl' end context 'when the user has Reporter permissions' do diff --git a/spec/requests/api/graphql/project/releases_spec.rb b/spec/requests/api/graphql/project/releases_spec.rb index 2816ce90a6b..c28a6fa7666 100644 --- a/spec/requests/api/graphql/project/releases_spec.rb +++ b/spec/requests/api/graphql/project/releases_spec.rb @@ -129,10 +129,12 @@ RSpec.describe 'Query.project(fullPath).releases()' do end it 'does not return data for fields that expose repository information' do + tag_name = release.tag + release_name = release.name expect(data).to eq( - 'tagName' => nil, + 'tagName' => tag_name, 'tagPath' => nil, - 'name' => "Release-#{release.id}", + 'name' => release_name, 'commit' => nil, 'assets' => { 'count' => release.assets_count(except: [:sources]), @@ -143,7 +145,14 @@ RSpec.describe 'Query.project(fullPath).releases()' do 'evidences' => { 'nodes' => [] }, - 'links' => nil + 'links' => { + 'closedIssuesUrl' => nil, + 'closedMergeRequestsUrl' => nil, + 'mergedMergeRequestsUrl' => nil, + 'openedIssuesUrl' => nil, + 'openedMergeRequestsUrl' => nil, + 'selfUrl' => project_release_url(project, release) + } ) end end diff --git a/spec/services/packages/npm/create_package_service_spec.rb b/spec/services/packages/npm/create_package_service_spec.rb index 9598355a640..b1beb2adb3b 100644 --- a/spec/services/packages/npm/create_package_service_spec.rb +++ b/spec/services/packages/npm/create_package_service_spec.rb @@ -73,6 +73,23 @@ RSpec.describe Packages::Npm::CreatePackageService do end end + described_class::PACKAGE_JSON_NOT_ALLOWED_FIELDS.each do |field| + context "with not allowed #{field} field" do + before do + params[:versions][version][field] = 'test' + end + + it 'is persisted without the field' do + expect { subject } + .to change { Packages::Package.count }.by(1) + .and change { Packages::Package.npm.count }.by(1) + .and change { Packages::Tag.count }.by(1) + .and change { Packages::Npm::Metadatum.count }.by(1) + expect(subject.npm_metadatum.package_json[field]).to be_blank + end + end + end + context 'with packages_npm_abbreviated_metadata disabled' do before do stub_feature_flags(packages_npm_abbreviated_metadata: false) diff --git a/spec/support/shared_examples/models/concerns/analytics/cycle_analytics/stage_event_model_examples.rb b/spec/support/shared_examples/models/concerns/analytics/cycle_analytics/stage_event_model_examples.rb index b853d517d83..d823e7ac221 100644 --- a/spec/support/shared_examples/models/concerns/analytics/cycle_analytics/stage_event_model_examples.rb +++ b/spec/support/shared_examples/models/concerns/analytics/cycle_analytics/stage_event_model_examples.rb @@ -36,8 +36,8 @@ RSpec.shared_examples 'StageEventModel' do described_class.issuable_id_column, :group_id, :project_id, - :milestone_id, :author_id, + :milestone_id, :state_id, :start_event_timestamp, :end_event_timestamp |