summaryrefslogtreecommitdiff
path: root/spec/requests
diff options
context:
space:
mode:
Diffstat (limited to 'spec/requests')
-rw-r--r--spec/requests/api/lint_spec.rb168
-rw-r--r--spec/requests/api/merge_request_approvals_spec.rb6
-rw-r--r--spec/requests/api/merge_request_diffs_spec.rb12
-rw-r--r--spec/requests/api/merge_requests_spec.rb30
-rw-r--r--spec/requests/api/npm_instance_packages_spec.rb2
-rw-r--r--spec/requests/api/npm_project_packages_spec.rb34
-rw-r--r--spec/requests/api/project_attributes.yml149
-rw-r--r--spec/requests/api/projects_spec.rb51
-rw-r--r--spec/requests/api/terraform/state_spec.rb2
-rw-r--r--spec/requests/api/todos_spec.rb8
10 files changed, 393 insertions, 69 deletions
diff --git a/spec/requests/api/lint_spec.rb b/spec/requests/api/lint_spec.rb
index 2653653c896..2316e702c3e 100644
--- a/spec/requests/api/lint_spec.rb
+++ b/spec/requests/api/lint_spec.rb
@@ -4,91 +4,136 @@ require 'spec_helper'
RSpec.describe API::Lint do
describe 'POST /ci/lint' do
- context 'with valid .gitlab-ci.yaml content' do
- let(:yaml_content) do
- File.read(Rails.root.join('spec/support/gitlab_stubs/gitlab_ci.yml'))
- end
+ context 'when signup settings are disabled' do
+ Gitlab::CurrentSettings.signup_enabled = false
- it 'passes validation without warnings or errors' do
- post api('/ci/lint'), params: { content: yaml_content }
+ context 'when unauthenticated' do
+ it 'returns authentication error' 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 eq([])
- expect(json_response['errors']).to eq([])
+ expect(response).to have_gitlab_http_status(:unauthorized)
+ end
end
- it 'outputs expanded yaml content' do
- post api('/ci/lint'), params: { content: yaml_content, include_merged_yaml: true }
+ context 'when authenticated' do
+ it 'returns unauthorized error' do
+ post api('/ci/lint'), params: { content: 'content' }
- expect(response).to have_gitlab_http_status(:ok)
- expect(json_response).to have_key('merged_yaml')
+ expect(response).to have_gitlab_http_status(:unauthorized)
+ end
end
end
- context 'with valid .gitlab-ci.yaml with warnings' do
- let(:yaml_content) { { job: { script: 'ls', rules: [{ when: 'always' }] } }.to_yaml }
+ context 'when signup settings are enabled' do
+ Gitlab::CurrentSettings.signup_enabled = true
- it 'passes validation but returns warnings' do
- post api('/ci/lint'), params: { content: yaml_content }
+ context 'when unauthenticated' do
+ it 'returns authentication error' do
+ post api('/ci/lint'), params: { content: '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['status']).to eq('valid')
- expect(json_response['errors']).to eq([])
+ expect(response).to have_gitlab_http_status(:unauthorized)
+ end
+ end
+
+ 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' }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
end
end
- context 'with an invalid .gitlab_ci.yml' do
- context 'with invalid syntax' do
- let(:yaml_content) { 'invalid content' }
+ context 'when authenticated' do
+ let_it_be(:api_user) { create(:user) }
- it 'responds with errors about invalid syntax' do
- post api('/ci/lint'), params: { content: yaml_content }
+ context 'with valid .gitlab-ci.yaml content' do
+ let(:yaml_content) do
+ File.read(Rails.root.join('spec/support/gitlab_stubs/gitlab_ci.yml'))
+ end
+
+ 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).to be_an Hash
+ expect(json_response['status']).to eq('valid')
expect(json_response['warnings']).to eq([])
- expect(json_response['errors']).to eq(['Invalid configuration format'])
+ expect(json_response['errors']).to eq([])
end
it 'outputs expanded yaml content' do
- post api('/ci/lint'), params: { content: yaml_content, include_merged_yaml: true }
+ 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
end
- context 'with invalid configuration' do
- let(:yaml_content) { '{ image: "ruby:2.7", services: ["postgres"], invalid }' }
+ context 'with valid .gitlab-ci.yaml with warnings' do
+ let(:yaml_content) { { job: { script: 'ls', rules: [{ when: 'always' }] } }.to_yaml }
- it 'responds with errors about invalid configuration' do
- post api('/ci/lint'), params: { content: yaml_content }
+ 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 invalid config should implement a script: or a trigger: keyword', 'jobs config should contain at least one visible job'])
+ expect(json_response['status']).to eq('valid')
+ expect(json_response['warnings']).not_to be_empty
+ expect(json_response['status']).to eq('valid')
+ expect(json_response['errors']).to eq([])
end
+ end
- it 'outputs expanded yaml content' do
- post api('/ci/lint'), 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'])
+ 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
+ end
+
+ context 'with invalid configuration' do
+ let(:yaml_content) { '{ image: "ruby:2.7", services: ["postgres"] }' }
+
+ 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'])
+ 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
end
end
- end
- context 'without the content parameter' do
- it 'responds with validation error about missing content' do
- post api('/ci/lint')
+ 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
@@ -364,6 +409,18 @@ RSpec.describe API::Lint do
expect(response).to have_gitlab_http_status(:not_found)
end
+
+ context 'when project is public' do
+ before do
+ project.update!(visibility_level: Gitlab::VisibilityLevel::PUBLIC)
+ end
+
+ it 'returns authentication error' do
+ ci_lint
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+ end
end
context 'when authenticated as non-member' do
@@ -387,13 +444,10 @@ RSpec.describe API::Lint do
context 'when running as dry run' do
let(:dry_run) { true }
- it 'returns pipeline creation error' do
+ it 'returns authentication error' do
ci_lint
- expect(response).to have_gitlab_http_status(:ok)
- expect(json_response['merged_yaml']).to eq(nil)
- expect(json_response['valid']).to eq(false)
- expect(json_response['errors']).to eq(['Insufficient permissions to create a new pipeline'])
+ expect(response).to have_gitlab_http_status(:forbidden)
end
end
@@ -410,7 +464,11 @@ RSpec.describe API::Lint do
)
end
- it_behaves_like 'valid project config'
+ it 'returns authentication error' do
+ ci_lint
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
end
end
end
diff --git a/spec/requests/api/merge_request_approvals_spec.rb b/spec/requests/api/merge_request_approvals_spec.rb
index fad5c3fb60e..b18f3017e03 100644
--- a/spec/requests/api/merge_request_approvals_spec.rb
+++ b/spec/requests/api/merge_request_approvals_spec.rb
@@ -21,6 +21,12 @@ RSpec.describe API::MergeRequestApprovals do
expect(response).to have_gitlab_http_status(:ok)
end
+
+ context 'when merge request author has only guest access' do
+ it_behaves_like 'rejects user from accessing merge request info' do
+ let(:url) { "/projects/#{project.id}/merge_requests/#{merge_request.iid}/approvals" }
+ end
+ end
end
describe 'POST :id/merge_requests/:merge_request_iid/approve' do
diff --git a/spec/requests/api/merge_request_diffs_spec.rb b/spec/requests/api/merge_request_diffs_spec.rb
index 2e6cbe7bee7..971fb5e991c 100644
--- a/spec/requests/api/merge_request_diffs_spec.rb
+++ b/spec/requests/api/merge_request_diffs_spec.rb
@@ -35,6 +35,12 @@ RSpec.describe API::MergeRequestDiffs, 'MergeRequestDiffs' do
get api("/projects/#{project.id}/merge_requests/0/versions", user)
expect(response).to have_gitlab_http_status(:not_found)
end
+
+ context 'when merge request author has only guest access' do
+ it_behaves_like 'rejects user from accessing merge request info' do
+ let(:url) { "/projects/#{project.id}/merge_requests/#{merge_request.iid}/versions" }
+ end
+ end
end
describe 'GET /projects/:id/merge_requests/:merge_request_iid/versions/:version_id' do
@@ -63,5 +69,11 @@ RSpec.describe API::MergeRequestDiffs, 'MergeRequestDiffs' do
get api("/projects/#{project.id}/merge_requests/#{non_existing_record_iid}/versions/#{merge_request_diff.id}", user)
expect(response).to have_gitlab_http_status(:not_found)
end
+
+ context 'when merge request author has only guest access' do
+ it_behaves_like 'rejects user from accessing merge request info' do
+ let(:url) { "/projects/#{project.id}/merge_requests/#{merge_request.iid}/versions/#{merge_request_diff.id}" }
+ end
+ end
end
end
diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb
index b459d3cd8d3..ad8e21bf4c1 100644
--- a/spec/requests/api/merge_requests_spec.rb
+++ b/spec/requests/api/merge_requests_spec.rb
@@ -1226,6 +1226,12 @@ RSpec.describe API::MergeRequests do
end
end
+ context 'when merge request author has only guest access' do
+ it_behaves_like 'rejects user from accessing merge request info' do
+ let(:url) { "/projects/#{project.id}/merge_requests/#{merge_request.iid}" }
+ end
+ end
+
context 'merge_request_metrics' do
let(:pipeline) { create(:ci_empty_pipeline) }
@@ -1411,6 +1417,12 @@ RSpec.describe API::MergeRequests do
it_behaves_like 'issuable participants endpoint' do
let(:entity) { create(:merge_request, :simple, milestone: milestone1, author: user, assignees: [user], source_project: project, target_project: project, source_branch: 'markdown', title: "Test", created_at: base_time) }
end
+
+ context 'when merge request author has only guest access' do
+ it_behaves_like 'rejects user from accessing merge request info' do
+ let(:url) { "/projects/#{project.id}/merge_requests/#{merge_request.iid}/participants" }
+ end
+ end
end
describe 'GET /projects/:id/merge_requests/:merge_request_iid/commits' do
@@ -1436,6 +1448,12 @@ RSpec.describe API::MergeRequests do
expect(response).to have_gitlab_http_status(:not_found)
end
+
+ context 'when merge request author has only guest access' do
+ it_behaves_like 'rejects user from accessing merge request info' do
+ let(:url) { "/projects/#{project.id}/merge_requests/#{merge_request.iid}/commits" }
+ end
+ end
end
describe 'GET /projects/:id/merge_requests/:merge_request_iid/:context_commits' do
@@ -1511,6 +1529,12 @@ RSpec.describe API::MergeRequests do
expect(response).to have_gitlab_http_status(:not_found)
end
+ context 'when merge request author has only guest access' do
+ it_behaves_like 'rejects user from accessing merge request info' do
+ let(:url) { "/projects/#{project.id}/merge_requests/#{merge_request.iid}/changes" }
+ end
+ end
+
it_behaves_like 'find an existing merge request'
it_behaves_like 'accesses diffs via raw_diffs'
@@ -1600,6 +1624,12 @@ RSpec.describe API::MergeRequests do
expect(response).to have_gitlab_http_status(:forbidden)
end
end
+
+ context 'when merge request author has only guest access' do
+ it_behaves_like 'rejects user from accessing merge request info' do
+ let(:url) { "/projects/#{project.id}/merge_requests/#{merge_request.iid}/pipelines" }
+ end
+ end
end
describe 'POST /projects/:id/merge_requests/:merge_request_iid/pipelines' do
diff --git a/spec/requests/api/npm_instance_packages_spec.rb b/spec/requests/api/npm_instance_packages_spec.rb
index 8299717b5c7..70c76067a6e 100644
--- a/spec/requests/api/npm_instance_packages_spec.rb
+++ b/spec/requests/api/npm_instance_packages_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe API::NpmInstancePackages do
include_context 'npm api setup'
describe 'GET /api/v4/packages/npm/*package_name' do
- it_behaves_like 'handling get metadata requests' do
+ it_behaves_like 'handling get metadata requests', scope: :instance do
let(:url) { api("/packages/npm/#{package_name}") }
end
end
diff --git a/spec/requests/api/npm_project_packages_spec.rb b/spec/requests/api/npm_project_packages_spec.rb
index 1421f20ac28..7ea238c0607 100644
--- a/spec/requests/api/npm_project_packages_spec.rb
+++ b/spec/requests/api/npm_project_packages_spec.rb
@@ -6,25 +6,25 @@ RSpec.describe API::NpmProjectPackages do
include_context 'npm api setup'
describe 'GET /api/v4/projects/:id/packages/npm/*package_name' do
- it_behaves_like 'handling get metadata requests' do
+ it_behaves_like 'handling get metadata requests', scope: :project do
let(:url) { api("/projects/#{project.id}/packages/npm/#{package_name}") }
end
end
describe 'GET /api/v4/projects/:id/packages/npm/-/package/*package_name/dist-tags' do
- it_behaves_like 'handling get dist tags requests' do
+ it_behaves_like 'handling get dist tags requests', scope: :project do
let(:url) { api("/projects/#{project.id}/packages/npm/-/package/#{package_name}/dist-tags") }
end
end
describe 'PUT /api/v4/projects/:id/packages/npm/-/package/*package_name/dist-tags/:tag' do
- it_behaves_like 'handling create dist tag requests' do
+ it_behaves_like 'handling create dist tag requests', scope: :project do
let(:url) { api("/projects/#{project.id}/packages/npm/-/package/#{package_name}/dist-tags/#{tag_name}") }
end
end
describe 'DELETE /api/v4/projects/:id/packages/npm/-/package/*package_name/dist-tags/:tag' do
- it_behaves_like 'handling delete dist tag requests' do
+ it_behaves_like 'handling delete dist tag requests', scope: :project do
let(:url) { api("/projects/#{project.id}/packages/npm/-/package/#{package_name}/dist-tags/#{tag_name}") }
end
end
@@ -32,10 +32,14 @@ RSpec.describe API::NpmProjectPackages do
describe 'GET /api/v4/projects/:id/packages/npm/*package_name/-/*file_name' do
let_it_be(:package_file) { package.package_files.first }
- let(:params) { {} }
- let(:url) { api("/projects/#{project.id}/packages/npm/#{package_file.package.name}/-/#{package_file.file_name}") }
+ let(:headers) { {} }
+ let(:url) { api("/projects/#{project.id}/packages/npm/#{package.name}/-/#{package_file.file_name}") }
- subject { get(url, params: params) }
+ subject { get(url, headers: headers) }
+
+ before do
+ project.add_developer(user)
+ end
shared_examples 'a package file that requires auth' do
it 'denies download with no token' do
@@ -45,7 +49,7 @@ RSpec.describe API::NpmProjectPackages do
end
context 'with access token' do
- let(:params) { { access_token: token.token } }
+ let(:headers) { build_token_auth_header(token.token) }
it 'returns the file' do
subject
@@ -56,7 +60,7 @@ RSpec.describe API::NpmProjectPackages do
end
context 'with job token' do
- let(:params) { { job_token: job.token } }
+ let(:headers) { build_token_auth_header(job.token) }
it 'returns the file' do
subject
@@ -86,7 +90,7 @@ RSpec.describe API::NpmProjectPackages do
it_behaves_like 'a package file that requires auth'
context 'with guest' do
- let(:params) { { access_token: token.token } }
+ let(:headers) { build_token_auth_header(token.token) }
it 'denies download when not enough permissions' do
project.add_guest(user)
@@ -108,7 +112,11 @@ RSpec.describe API::NpmProjectPackages do
end
describe 'PUT /api/v4/projects/:id/packages/npm/:package_name' do
- RSpec.shared_examples 'handling invalid record with 400 error' do
+ before do
+ project.add_developer(user)
+ end
+
+ shared_examples 'handling invalid record with 400 error' do
it 'handles an ActiveRecord::RecordInvalid exception with 400 error' do
expect { upload_package_with_token(package_name, params) }
.not_to change { project.packages.count }
@@ -261,7 +269,9 @@ RSpec.describe API::NpmProjectPackages do
end
def upload_package(package_name, params = {})
- put api("/projects/#{project.id}/packages/npm/#{package_name.sub('/', '%2f')}"), params: params
+ token = params.delete(:access_token) || params.delete(:job_token)
+ headers = build_token_auth_header(token)
+ put api("/projects/#{project.id}/packages/npm/#{package_name.sub('/', '%2f')}"), params: params, headers: headers
end
def upload_package_with_token(package_name, params = {})
diff --git a/spec/requests/api/project_attributes.yml b/spec/requests/api/project_attributes.yml
new file mode 100644
index 00000000000..181fcafd577
--- /dev/null
+++ b/spec/requests/api/project_attributes.yml
@@ -0,0 +1,149 @@
+---
+itself: # project
+ unexposed_attributes:
+ - bfg_object_map
+ - delete_error
+ - detected_repository_languages
+ - disable_overriding_approvers_per_merge_request
+ - external_authorization_classification_label
+ - external_webhook_token
+ - has_external_issue_tracker
+ - has_external_wiki
+ - import_source
+ - import_type
+ - import_url
+ - issues_template
+ - jobs_cache_index
+ - last_repository_check_at
+ - last_repository_check_failed
+ - last_repository_updated_at
+ - marked_for_deletion_at
+ - marked_for_deletion_by_user_id
+ - max_artifacts_size
+ - max_pages_size
+ - merge_requests_author_approval
+ - merge_requests_disable_committers_approval
+ - merge_requests_rebase_enabled
+ - merge_requests_template
+ - mirror_last_successful_update_at
+ - mirror_last_update_at
+ - mirror_overwrites_diverged_branches
+ - mirror_trigger_builds
+ - mirror_user_id
+ - only_mirror_protected_branches
+ - pages_https_only
+ - pending_delete
+ - pool_repository_id
+ - pull_mirror_available_overridden
+ - pull_mirror_branch_prefix
+ - remote_mirror_available_overridden
+ - repository_read_only
+ - repository_size_limit
+ - require_password_to_approve
+ - reset_approvals_on_push
+ - runners_token_encrypted
+ - storage_version
+ - updated_at
+ remapped_attributes:
+ avatar: avatar_url
+ build_allow_git_fetch: build_git_strategy
+ merge_requests_ff_only_enabled: merge_method
+ namespace_id: namespace
+ public_builds: public_jobs
+ visibility_level: visibility
+ computed_attributes:
+ - _links
+ - can_create_merge_request_in
+ - compliance_frameworks
+ - container_expiration_policy
+ - default_branch
+ - empty_repo
+ - forks_count
+ - http_url_to_repo
+ - name_with_namespace
+ - open_issues_count
+ - owner
+ - path_with_namespace
+ - permissions
+ - readme_url
+ - shared_with_groups
+ - ssh_url_to_repo
+ - web_url
+
+build_auto_devops: # auto_devops
+ unexposed_attributes:
+ - id
+ - project_id
+ - created_at
+ - updated_at
+ remapped_attributes:
+ enabled: auto_devops_enabled
+ deploy_strategy: auto_devops_deploy_strategy
+
+ci_cd_settings:
+ unexposed_attributes:
+ - id
+ - project_id
+ - group_runners_enabled
+ - keep_latest_artifact
+ - merge_pipelines_enabled
+ - merge_trains_enabled
+ - auto_rollback_enabled
+ remapped_attributes:
+ default_git_depth: ci_default_git_depth
+ forward_deployment_enabled: ci_forward_deployment_enabled
+
+build_import_state: # import_state
+ unexposed_attributes:
+ - id
+ - project_id
+ - retry_count
+ - last_update_started_at
+ - last_update_scheduled_at
+ - next_execution_timestamp
+ - jid
+ - last_update_at
+ - last_successful_update_at
+ - correlation_id_value
+ remapped_attributes:
+ status: import_status
+ last_error: import_error
+
+project_feature:
+ unexposed_attributes:
+ - id
+ - created_at
+ - metrics_dashboard_access_level
+ - project_id
+ - requirements_access_level
+ - security_and_compliance_access_level
+ - updated_at
+ computed_attributes:
+ - issues_enabled
+ - jobs_enabled
+ - merge_requests_enabled
+ - requirements_enabled
+ - security_and_compliance_enabled
+ - snippets_enabled
+ - wiki_enabled
+
+project_setting:
+ unexposed_attributes:
+ - allow_editing_commit_messages
+ - created_at
+ - has_confluence
+ - has_vulnerabilities
+ - prevent_merge_without_jira_issue
+ - project_id
+ - push_rule_id
+ - show_default_award_emojis
+ - squash_option
+ - updated_at
+
+build_service_desk_setting: # service_desk_setting
+ unexposed_attributes:
+ - project_id
+ - issue_template_key
+ - outgoing_name
+ remapped_attributes:
+ project_key: service_desk_address
diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb
index 6d8cdde2c4f..ad36777184a 100644
--- a/spec/requests/api/projects_spec.rb
+++ b/spec/requests/api/projects_spec.rb
@@ -886,6 +886,7 @@ RSpec.describe API::Projects do
merge_method: 'ff'
}).tap do |attrs|
attrs[:operations_access_level] = 'disabled'
+ attrs[:analytics_access_level] = 'disabled'
end
post api('/projects', user), params: project
@@ -1539,6 +1540,35 @@ RSpec.describe API::Projects do
end
context 'when authenticated as an admin' do
+ let(:project_attributes_file) { 'spec/requests/api/project_attributes.yml' }
+ let(:project_attributes) { YAML.load_file(project_attributes_file) }
+
+ let(:expected_keys) do
+ keys = project_attributes.map do |relation, relation_config|
+ begin
+ actual_keys = project.send(relation).attributes.keys
+ rescue NoMethodError
+ actual_keys = ["#{relation} is nil"]
+ end
+ unexposed_attributes = relation_config['unexposed_attributes'] || []
+ remapped_attributes = relation_config['remapped_attributes'] || {}
+ computed_attributes = relation_config['computed_attributes'] || []
+ actual_keys - unexposed_attributes - remapped_attributes.keys + remapped_attributes.values + computed_attributes
+ end.flatten
+
+ unless Gitlab.ee?
+ keys -= %w[
+ approvals_before_merge
+ compliance_frameworks
+ mirror
+ requirements_enabled
+ security_and_compliance_enabled
+ ]
+ end
+
+ keys
+ end
+
it 'returns a project by id' do
project
project_member
@@ -1587,6 +1617,27 @@ RSpec.describe API::Projects do
expect(json_response['only_allow_merge_if_all_discussions_are_resolved']).to eq(project.only_allow_merge_if_all_discussions_are_resolved)
expect(json_response['operations_access_level']).to be_present
end
+
+ it 'exposes all necessary attributes' do
+ create(:project_group_link, project: project)
+
+ get api("/projects/#{project.id}", admin)
+
+ diff = Set.new(json_response.keys) ^ Set.new(expected_keys)
+
+ expect(diff).to be_empty, failure_message(diff)
+ end
+
+ def failure_message(diff)
+ <<~MSG
+ It looks like project's set of exposed attributes is different from the expected set.
+
+ The following attributes are missing or newly added:
+ #{diff.to_a.to_sentence}
+
+ Please update #{project_attributes_file} file"
+ MSG
+ end
end
context 'when authenticated as a regular user' do
diff --git a/spec/requests/api/terraform/state_spec.rb b/spec/requests/api/terraform/state_spec.rb
index bfdb5458fd1..2cb3c8e9ab5 100644
--- a/spec/requests/api/terraform/state_spec.rb
+++ b/spec/requests/api/terraform/state_spec.rb
@@ -39,7 +39,7 @@ RSpec.describe API::Terraform::State do
context 'with maintainer permissions' do
let(:current_user) { maintainer }
- it_behaves_like 'tracking unique hll events', :usage_data_p_terraform_state_api_unique_users do
+ it_behaves_like 'tracking unique hll events' do
let(:target_id) { 'p_terraform_state_api_unique_users' }
let(:expected_type) { instance_of(Integer) }
end
diff --git a/spec/requests/api/todos_spec.rb b/spec/requests/api/todos_spec.rb
index eaffa49fc9d..00de1ef5964 100644
--- a/spec/requests/api/todos_spec.rb
+++ b/spec/requests/api/todos_spec.rb
@@ -331,6 +331,14 @@ RSpec.describe API::Todos do
expect(response).to have_gitlab_http_status(:not_found)
end
end
+
+ it 'returns an error if the issuable author does not have access' do
+ project_1.add_guest(issuable.author)
+
+ post api("/projects/#{project_1.id}/#{issuable_type}/#{issuable.iid}/todo", issuable.author)
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
end
describe 'POST :id/issuable_type/:issueable_id/todo' do