diff --git a/config/authz/permission_groups/assignable_permissions/project_features/snippet/create.yml b/config/authz/permission_groups/assignable_permissions/project_features/snippet/create.yml new file mode 100644 index 0000000000000000000000000000000000000000..c81a1cd337363394f07341b54f200a6f9308f67e --- /dev/null +++ b/config/authz/permission_groups/assignable_permissions/project_features/snippet/create.yml @@ -0,0 +1,8 @@ +--- +name: create_snippet +description: Grants the ability to create snippets +feature_category: source_code_management +boundaries: + - instance +permissions: + - create_snippet diff --git a/config/authz/permission_groups/assignable_permissions/project_features/snippet/delete.yml b/config/authz/permission_groups/assignable_permissions/project_features/snippet/delete.yml new file mode 100644 index 0000000000000000000000000000000000000000..0f86bd56eee55feb1bac40bd1605113e94245a58 --- /dev/null +++ b/config/authz/permission_groups/assignable_permissions/project_features/snippet/delete.yml @@ -0,0 +1,8 @@ +--- +name: delete_snippet +description: Grants the ability to delete snippets +feature_category: source_code_management +boundaries: + - instance +permissions: + - delete_snippet diff --git a/config/authz/permission_groups/assignable_permissions/project_features/snippet/read.yml b/config/authz/permission_groups/assignable_permissions/project_features/snippet/read.yml new file mode 100644 index 0000000000000000000000000000000000000000..8ac17600adb217cbb0c18752a346720eb04c568d --- /dev/null +++ b/config/authz/permission_groups/assignable_permissions/project_features/snippet/read.yml @@ -0,0 +1,8 @@ +--- +name: read_snippet +description: Grants the ability to read snippets +feature_category: source_code_management +boundaries: + - instance +permissions: + - read_snippet diff --git a/config/authz/permission_groups/assignable_permissions/project_features/snippet/read_all.yml b/config/authz/permission_groups/assignable_permissions/project_features/snippet/read_all.yml new file mode 100644 index 0000000000000000000000000000000000000000..52b7c4bc5abc93449bf72560d59dc0e3cf3492c7 --- /dev/null +++ b/config/authz/permission_groups/assignable_permissions/project_features/snippet/read_all.yml @@ -0,0 +1,8 @@ +--- +name: read_all_snippet +description: Grants the ability to read all snippets +feature_category: source_code_management +boundaries: + - instance +permissions: + - read_all_snippet diff --git a/config/authz/permission_groups/assignable_permissions/project_features/snippet_user_agent_detail/read.yml b/config/authz/permission_groups/assignable_permissions/project_features/snippet_user_agent_detail/read.yml new file mode 100644 index 0000000000000000000000000000000000000000..7fbea838efd27dee59c0209bf8aa3b0b7aa2f74b --- /dev/null +++ b/config/authz/permission_groups/assignable_permissions/project_features/snippet_user_agent_detail/read.yml @@ -0,0 +1,8 @@ +--- +name: read_snippet_user_agent_detail +description: Grants the ability to read snippet user agent details +feature_category: source_code_management +boundaries: + - instance +permissions: + - read_snippet_user_agent_detail diff --git a/config/authz/permissions/definitions_todo.txt b/config/authz/permissions/definitions_todo.txt index 1814b72928b550517a7ceea264ea52c49d062d8a..cdf3723322e6d319a92e1dd471ad38986ba4d02f 100644 --- a/config/authz/permissions/definitions_todo.txt +++ b/config/authz/permissions/definitions_todo.txt @@ -248,7 +248,6 @@ create_runners create_saved_replies create_sentry_issue create_service_account -create_snippet create_squash_option create_subgroup create_task @@ -668,7 +667,6 @@ read_security_settings read_self_hosted_models_settings read_sentry_issue read_shared_with_group -read_snippet read_software_license_policy read_squash_option read_statistics @@ -831,7 +829,6 @@ update_saved_replies update_secret_detection_validity_checks_status update_security_orchestration_policy_project update_sentry_issue -update_snippet update_squash_option update_subscription update_subscription_limit diff --git a/config/authz/permissions/snippet/_metadata.yml b/config/authz/permissions/snippet/_metadata.yml new file mode 100644 index 0000000000000000000000000000000000000000..8fe5b8de7a2906f1681460ec55e851b6b1d81ba1 --- /dev/null +++ b/config/authz/permissions/snippet/_metadata.yml @@ -0,0 +1 @@ +feature_category: source_code_management diff --git a/config/authz/permissions/snippet/create.yml b/config/authz/permissions/snippet/create.yml new file mode 100644 index 0000000000000000000000000000000000000000..1e86d0803de8d43b7f8260c07eb04f1818530c00 --- /dev/null +++ b/config/authz/permissions/snippet/create.yml @@ -0,0 +1,6 @@ +--- +name: create_snippet +description: Grants the ability to create snippets +feature_category: source_code_management +boundaries: + - instance diff --git a/config/authz/permissions/snippet/delete.yml b/config/authz/permissions/snippet/delete.yml new file mode 100644 index 0000000000000000000000000000000000000000..a411a2a60c203ddc856abbf43340c15afa0d449b --- /dev/null +++ b/config/authz/permissions/snippet/delete.yml @@ -0,0 +1,6 @@ +--- +name: delete_snippet +description: Grants the ability to delete snippets +feature_category: source_code_management +boundaries: + - instance diff --git a/config/authz/permissions/snippet/read.yml b/config/authz/permissions/snippet/read.yml new file mode 100644 index 0000000000000000000000000000000000000000..dd7955fb8f6a3f132b0db300b1f519e4f1c68613 --- /dev/null +++ b/config/authz/permissions/snippet/read.yml @@ -0,0 +1,6 @@ +--- +name: read_snippet +description: Grants the ability to read snippets +feature_category: source_code_management +boundaries: + - instance diff --git a/config/authz/permissions/snippet/read_all.yml b/config/authz/permissions/snippet/read_all.yml new file mode 100644 index 0000000000000000000000000000000000000000..764fe8fd394597e412b50a018856c4b873742634 --- /dev/null +++ b/config/authz/permissions/snippet/read_all.yml @@ -0,0 +1,6 @@ +--- +name: read_all_snippet +description: Grants the ability to read all snippets the user has access to +feature_category: source_code_management +boundaries: + - instance diff --git a/config/authz/permissions/snippet/update.yml b/config/authz/permissions/snippet/update.yml new file mode 100644 index 0000000000000000000000000000000000000000..ceb6100cbe25abe9eb874dd9d952b16d429513ff --- /dev/null +++ b/config/authz/permissions/snippet/update.yml @@ -0,0 +1,6 @@ +--- +name: update_snippet +description: Grants the ability to update snippets +feature_category: source_code_management +boundaries: + - instance diff --git a/config/authz/permissions/snippet_user_agent_detail/_metadata.yml b/config/authz/permissions/snippet_user_agent_detail/_metadata.yml new file mode 100644 index 0000000000000000000000000000000000000000..8fe5b8de7a2906f1681460ec55e851b6b1d81ba1 --- /dev/null +++ b/config/authz/permissions/snippet_user_agent_detail/_metadata.yml @@ -0,0 +1 @@ +feature_category: source_code_management diff --git a/config/authz/permissions/snippet_user_agent_detail/read.yml b/config/authz/permissions/snippet_user_agent_detail/read.yml new file mode 100644 index 0000000000000000000000000000000000000000..1f4cc5ed74aa71f34575bc09ed7287d75f7757e7 --- /dev/null +++ b/config/authz/permissions/snippet_user_agent_detail/read.yml @@ -0,0 +1,6 @@ +--- +name: read_snippet_user_agent_detail +description: Grants the ability to read snippet user agent details +feature_category: source_code_management +boundaries: + - instance diff --git a/lib/api/snippets.rb b/lib/api/snippets.rb index 0dc7542f889bf3333ab73126c05f833c6f4811c4..8df45f04389c890a7196e92d8e42e96cba7035f7 100644 --- a/lib/api/snippets.rb +++ b/lib/api/snippets.rb @@ -45,6 +45,7 @@ def find_snippet(id) use :pagination end + route_setting :authorization, permissions: :read_snippet, boundary_type: :instance get do authenticate! @@ -68,6 +69,7 @@ def find_snippet(id) use :pagination end + route_setting :authorization, permissions: :read_snippet, boundary_type: :instance get 'public' do authenticate! @@ -96,6 +98,7 @@ def find_snippet(id) use :pagination use :optional_list_params_ee end + route_setting :authorization, permissions: :read_all_snippets, boundary_type: :instance get 'all' do authenticate! @@ -115,6 +118,7 @@ def find_snippet(id) params do requires :id, type: Integer, desc: 'The ID of a snippet' end + route_setting :authorization, permissions: :read_snippet, boundary_type: :instance get ':id' do snippet = find_snippet(params[:id]) @@ -143,6 +147,7 @@ def find_snippet(id) use :create_file_params end + route_setting :authorization, permissions: :create_snippet, boundary_type: :instance post do authenticate! @@ -189,6 +194,7 @@ def find_snippet(id) use :update_file_params use :minimum_update_params end + route_setting :authorization, permissions: :update_snippet, boundary_type: :instance put ':id' do authenticate! @@ -231,6 +237,7 @@ def find_snippet(id) params do requires :id, type: Integer, desc: 'The ID of a snippet' end + route_setting :authorization, permissions: :delete_snippet, boundary_type: :instance delete ':id' do authenticate! @@ -260,6 +267,7 @@ def find_snippet(id) params do requires :id, type: Integer, desc: 'The ID of a snippet' end + route_setting :authorization, permissions: :read_snippet, boundary_type: :instance get ":id/raw" do snippet = find_snippet(params.delete(:id)) not_found!('Snippet') unless snippet @@ -276,6 +284,7 @@ def find_snippet(id) params do use :raw_file_params end + route_setting :authorization, permissions: :read_snippet, boundary_type: :instance get ":id/files/:ref/:file_path/raw", requirements: { file_path: API::NO_SLASH_URL_PART_REGEX } do snippet = find_snippet(params.delete(:id)) not_found!('Snippet') unless snippet&.repo_exists? @@ -293,6 +302,7 @@ def find_snippet(id) params do requires :id, type: Integer, desc: 'The ID of a snippet' end + route_setting :authorization, permissions: :read_snippet_user_agent_detail, boundary_type: :instance get ":id/user_agent_detail" do authenticated_as_admin! diff --git a/spec/requests/api/snippets_spec.rb b/spec/requests/api/snippets_spec.rb index ecd5310e361d16c0cd2b37c62aa14ac229ec3994..174243612369aa6a319db9e543538daa78a68a20 100644 --- a/spec/requests/api/snippets_spec.rb +++ b/spec/requests/api/snippets_spec.rb @@ -90,6 +90,13 @@ expect(snippet["id"]).not_to eq(public_snippet.id) end end + + it_behaves_like 'authorizing granular token permissions', :read_snippet do + let(:boundary_object) { nil } + let(:request) do + get api("/snippets", personal_access_token: pat) + end + end end describe 'GET /snippets/public' do @@ -136,6 +143,13 @@ public_snippet_in_time_range.id) end end + + it_behaves_like 'authorizing granular token permissions', :read_snippet do + let(:boundary_object) { nil } + let(:request) do + get api("/snippets/public", personal_access_token: pat) + end + end end describe 'GET /snippets/all' do @@ -179,6 +193,13 @@ end end end + + it_behaves_like 'authorizing granular token permissions', :read_all_snippets do + let(:boundary_object) { nil } + let(:request) do + get api("/snippets/all", personal_access_token: pat) + end + end end describe 'GET /snippets/:id/raw' do @@ -211,6 +232,13 @@ subject { get api("/snippets/#{snippet.id}/raw", snippet.author, personal_access_token: user_token) } end + + it_behaves_like 'authorizing granular token permissions', :read_snippet do + let(:boundary_object) { nil } + let(:request) do + get api("/snippets/#{private_snippet.id}/raw", personal_access_token: pat) + end + end end describe 'GET /snippets/:id/files/:ref/:file_path/raw' do @@ -223,6 +251,13 @@ it_behaves_like 'snippet access with different users' do let(:path) { "/snippets/#{snippet.id}/files/master/%2Egitattributes/raw" } end + + it_behaves_like 'authorizing granular token permissions', :read_snippet do + let(:boundary_object) { nil } + let(:request) do + get api("/snippets/#{private_snippet.id}/files/master/%2Egitattributes/raw", personal_access_token: pat) + end + end end describe 'GET /snippets/:id' do @@ -260,6 +295,13 @@ it_behaves_like 'snippet access with different users' do let(:path) { "/snippets/#{snippet.id}" } end + + it_behaves_like 'authorizing granular token permissions', :read_snippet do + let(:boundary_object) { nil } + let(:request) do + get api("/snippets/#{private_snippet.id}", personal_access_token: pat) + end + end end describe 'POST /snippets/', :with_current_organization do @@ -426,6 +468,13 @@ end end end + + it_behaves_like 'authorizing granular token permissions', :create_snippet do + let(:boundary_object) { nil } + let(:request) do + post api("/snippets/", personal_access_token: pat), params: { title: 'Test Title', description: 'test description', visibility: 'public', files: [{ file_path: 'file_1.rb', content: 'puts "hello world"' }] } + end + end end describe 'PUT /snippets/:id' do @@ -533,6 +582,14 @@ def update_snippet(snippet_id: snippet.id, params: {}, requester: user) put api("/snippets/#{snippet_id}", requester), params: params end + + it_behaves_like 'authorizing granular token permissions', :update_snippet do + let(:snippet) { create(:personal_snippet, :repository, author: user, visibility_level: Snippet::PUBLIC) } + let(:boundary_object) { nil } + let(:request) do + put api("/snippets/#{snippet.id}", personal_access_token: pat), params: { title: 'Updated Title' } + end + end end describe 'DELETE /snippets/:id' do @@ -578,6 +635,14 @@ def update_snippet(snippet_id: snippet.id, params: {}, requester: user) it_behaves_like '412 response' do let(:request) { api("/snippets/#{public_snippet.id}", personal_access_token: user_token) } end + + it_behaves_like 'authorizing granular token permissions', :delete_snippet do + let(:snippet_to_delete) { create(:personal_snippet, :repository, author: user) } + let(:boundary_object) { nil } + let(:request) do + delete api("/snippets/#{snippet_to_delete.id}", personal_access_token: pat) + end + end end describe "GET /snippets/:id/user_agent_detail" do @@ -595,5 +660,12 @@ def update_snippet(snippet_id: snippet.id, params: {}, requester: user) expect(json_response['ip_address']).to eq(user_agent_detail.ip_address) expect(json_response['akismet_submitted']).to eq(user_agent_detail.submitted) end + + it_behaves_like 'authorizing granular token permissions', :read_snippet_user_agent_detail do + let(:boundary_object) { nil } + let(:request) do + get api("/snippets/#{public_snippet.id}/user_agent_detail", personal_access_token: pat) + end + end end end