diff --git a/app/finders/concerns/packages/finder_helper.rb b/app/finders/concerns/packages/finder_helper.rb index 244bd7f6f86fd49212736e7937414fc533af142c..39c018818d1237c58e7411f945fc70d3c088121f 100644 --- a/app/finders/concerns/packages/finder_helper.rb +++ b/app/finders/concerns/packages/finder_helper.rb @@ -13,7 +13,7 @@ def packages_visible_to_user(user, within_group:) return ::Packages::Package.none unless within_group return ::Packages::Package.none unless Ability.allowed?(user, :read_group, within_group) - projects = projects_visible_to_reporters(user, within_group.self_and_descendants.select(:id)) + projects = projects_visible_to_reporters(user, within_group: within_group) ::Packages::Package.for_projects(projects.select(:id)) end @@ -21,12 +21,16 @@ def projects_visible_to_user(user, within_group:) return ::Project.none unless within_group return ::Project.none unless Ability.allowed?(user, :read_group, within_group) - projects_visible_to_reporters(user, within_group.self_and_descendants.select(:id)) + projects_visible_to_reporters(user, within_group: within_group) end - def projects_visible_to_reporters(user, namespace_ids) - ::Project.in_namespace(namespace_ids) - .public_or_visible_to_user(user, ::Gitlab::Access::REPORTER) + def projects_visible_to_reporters(user, within_group:) + if user.is_a?(DeployToken) && Feature.enabled?(:packages_finder_helper_deploy_token) + user.accessible_projects + else + within_group.all_projects + .public_or_visible_to_user(user, ::Gitlab::Access::REPORTER) + end end def package_type diff --git a/config/feature_flags/development/packages_finder_helper_deploy_token.yml b/config/feature_flags/development/packages_finder_helper_deploy_token.yml new file mode 100644 index 0000000000000000000000000000000000000000..fcc73cafd647dc7521e9b8454ccf9a2b7771932b --- /dev/null +++ b/config/feature_flags/development/packages_finder_helper_deploy_token.yml @@ -0,0 +1,8 @@ +--- +name: packages_finder_helper_deploy_token +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/58497 +rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/326808 +milestone: '13.11' +type: development +group: group::package +default_enabled: false diff --git a/spec/finders/concerns/packages/finder_helper_spec.rb b/spec/finders/concerns/packages/finder_helper_spec.rb index 73f7764757312d6316bc004c3107458bececb679..c1740ee17964da5199c4040ade99ccd367cd6ca9 100644 --- a/spec/finders/concerns/packages/finder_helper_spec.rb +++ b/spec/finders/concerns/packages/finder_helper_spec.rb @@ -6,7 +6,6 @@ describe '#packages_visible_to_user' do using RSpec::Parameterized::TableSyntax - let_it_be(:user) { create(:user) } let_it_be_with_reload(:group) { create(:group) } let_it_be_with_reload(:project1) { create(:project, namespace: group) } let_it_be(:package1) { create(:package, project: project1) } @@ -44,41 +43,87 @@ def execute(group) it { is_expected.to be_empty } end - where(:group_visibility, :subgroup_visibility, :project2_visibility, :user_role, :shared_example_name) do - 'PUBLIC' | 'PUBLIC' | 'PUBLIC' | :maintainer | 'returning both packages' - 'PUBLIC' | 'PUBLIC' | 'PUBLIC' | :developer | 'returning both packages' - 'PUBLIC' | 'PUBLIC' | 'PUBLIC' | :guest | 'returning both packages' - 'PUBLIC' | 'PUBLIC' | 'PUBLIC' | :anonymous | 'returning both packages' - 'PUBLIC' | 'PUBLIC' | 'PRIVATE' | :maintainer | 'returning both packages' - 'PUBLIC' | 'PUBLIC' | 'PRIVATE' | :developer | 'returning both packages' - 'PUBLIC' | 'PUBLIC' | 'PRIVATE' | :guest | 'returning package1' - 'PUBLIC' | 'PUBLIC' | 'PRIVATE' | :anonymous | 'returning package1' - 'PUBLIC' | 'PRIVATE' | 'PRIVATE' | :maintainer | 'returning both packages' - 'PUBLIC' | 'PRIVATE' | 'PRIVATE' | :developer | 'returning both packages' - 'PUBLIC' | 'PRIVATE' | 'PRIVATE' | :guest | 'returning package1' - 'PUBLIC' | 'PRIVATE' | 'PRIVATE' | :anonymous | 'returning package1' - 'PRIVATE' | 'PRIVATE' | 'PRIVATE' | :maintainer | 'returning both packages' - 'PRIVATE' | 'PRIVATE' | 'PRIVATE' | :developer | 'returning both packages' - 'PRIVATE' | 'PRIVATE' | 'PRIVATE' | :guest | 'returning no packages' - 'PRIVATE' | 'PRIVATE' | 'PRIVATE' | :anonymous | 'returning no packages' + context 'with a user' do + let_it_be(:user) { create(:user) } + + where(:group_visibility, :subgroup_visibility, :project2_visibility, :user_role, :shared_example_name) do + 'PUBLIC' | 'PUBLIC' | 'PUBLIC' | :maintainer | 'returning both packages' + 'PUBLIC' | 'PUBLIC' | 'PUBLIC' | :developer | 'returning both packages' + 'PUBLIC' | 'PUBLIC' | 'PUBLIC' | :guest | 'returning both packages' + 'PUBLIC' | 'PUBLIC' | 'PUBLIC' | :anonymous | 'returning both packages' + 'PUBLIC' | 'PUBLIC' | 'PRIVATE' | :maintainer | 'returning both packages' + 'PUBLIC' | 'PUBLIC' | 'PRIVATE' | :developer | 'returning both packages' + 'PUBLIC' | 'PUBLIC' | 'PRIVATE' | :guest | 'returning package1' + 'PUBLIC' | 'PUBLIC' | 'PRIVATE' | :anonymous | 'returning package1' + 'PUBLIC' | 'PRIVATE' | 'PRIVATE' | :maintainer | 'returning both packages' + 'PUBLIC' | 'PRIVATE' | 'PRIVATE' | :developer | 'returning both packages' + 'PUBLIC' | 'PRIVATE' | 'PRIVATE' | :guest | 'returning package1' + 'PUBLIC' | 'PRIVATE' | 'PRIVATE' | :anonymous | 'returning package1' + 'PRIVATE' | 'PRIVATE' | 'PRIVATE' | :maintainer | 'returning both packages' + 'PRIVATE' | 'PRIVATE' | 'PRIVATE' | :developer | 'returning both packages' + 'PRIVATE' | 'PRIVATE' | 'PRIVATE' | :guest | 'returning no packages' + 'PRIVATE' | 'PRIVATE' | 'PRIVATE' | :anonymous | 'returning no packages' + end + + with_them do + before do + unless user_role == :anonymous + group.send("add_#{user_role}", user) + subgroup.send("add_#{user_role}", user) + project1.send("add_#{user_role}", user) + project2.send("add_#{user_role}", user) + end + + project2.update!(visibility_level: Gitlab::VisibilityLevel.const_get(project2_visibility, false)) + subgroup.update!(visibility_level: Gitlab::VisibilityLevel.const_get(subgroup_visibility, false)) + project1.update!(visibility_level: Gitlab::VisibilityLevel.const_get(group_visibility, false)) + group.update!(visibility_level: Gitlab::VisibilityLevel.const_get(group_visibility, false)) + end + + it_behaves_like params[:shared_example_name] + end end - with_them do - before do - unless user_role == :anonymous - group.send("add_#{user_role}", user) - subgroup.send("add_#{user_role}", user) - project1.send("add_#{user_role}", user) - project2.send("add_#{user_role}", user) + context 'with a group deploy token' do + let_it_be(:user) { create(:deploy_token, :group, read_package_registry: true) } + let_it_be(:group_deploy_token) { create(:group_deploy_token, deploy_token: user, group: group) } + + shared_examples 'handling all conditions' do + where(:group_visibility, :subgroup_visibility, :project2_visibility, :shared_example_name) do + 'PUBLIC' | 'PUBLIC' | 'PUBLIC' | 'returning both packages' + 'PUBLIC' | 'PUBLIC' | 'PRIVATE' | 'returning both packages' + 'PUBLIC' | 'PRIVATE' | 'PRIVATE' | 'returning both packages' + 'PRIVATE' | 'PRIVATE' | 'PRIVATE' | 'returning both packages' + end + + with_them do + before do + project2.update!(visibility_level: Gitlab::VisibilityLevel.const_get(project2_visibility, false)) + subgroup.update!(visibility_level: Gitlab::VisibilityLevel.const_get(subgroup_visibility, false)) + project1.update!(visibility_level: Gitlab::VisibilityLevel.const_get(group_visibility, false)) + group.update!(visibility_level: Gitlab::VisibilityLevel.const_get(group_visibility, false)) + end + + it_behaves_like params[:shared_example_name] + end + end + + context 'with packages_finder_helper_deploy_token enabled' do + before do + expect(group).not_to receive(:all_projects) end - project2.update!(visibility_level: Gitlab::VisibilityLevel.const_get(project2_visibility, false)) - subgroup.update!(visibility_level: Gitlab::VisibilityLevel.const_get(subgroup_visibility, false)) - project1.update!(visibility_level: Gitlab::VisibilityLevel.const_get(group_visibility, false)) - group.update!(visibility_level: Gitlab::VisibilityLevel.const_get(group_visibility, false)) + it_behaves_like 'handling all conditions' end - it_behaves_like params[:shared_example_name] + context 'with packages_finder_helper_deploy_token disabled' do + before do + stub_feature_flags(packages_finder_helper_deploy_token: false) + expect(group).to receive(:all_projects).and_call_original + end + + it_behaves_like 'handling all conditions' + end end end @@ -121,41 +166,87 @@ def execute(group) it { is_expected.to be_empty } end - where(:group_visibility, :subgroup_visibility, :project2_visibility, :user_role, :shared_example_name) do - 'PUBLIC' | 'PUBLIC' | 'PUBLIC' | :maintainer | 'returning both projects' - 'PUBLIC' | 'PUBLIC' | 'PUBLIC' | :developer | 'returning both projects' - 'PUBLIC' | 'PUBLIC' | 'PUBLIC' | :guest | 'returning both projects' - 'PUBLIC' | 'PUBLIC' | 'PUBLIC' | :anonymous | 'returning both projects' - 'PUBLIC' | 'PUBLIC' | 'PRIVATE' | :maintainer | 'returning both projects' - 'PUBLIC' | 'PUBLIC' | 'PRIVATE' | :developer | 'returning both projects' - 'PUBLIC' | 'PUBLIC' | 'PRIVATE' | :guest | 'returning project1' - 'PUBLIC' | 'PUBLIC' | 'PRIVATE' | :anonymous | 'returning project1' - 'PUBLIC' | 'PRIVATE' | 'PRIVATE' | :maintainer | 'returning both projects' - 'PUBLIC' | 'PRIVATE' | 'PRIVATE' | :developer | 'returning both projects' - 'PUBLIC' | 'PRIVATE' | 'PRIVATE' | :guest | 'returning project1' - 'PUBLIC' | 'PRIVATE' | 'PRIVATE' | :anonymous | 'returning project1' - 'PRIVATE' | 'PRIVATE' | 'PRIVATE' | :maintainer | 'returning both projects' - 'PRIVATE' | 'PRIVATE' | 'PRIVATE' | :developer | 'returning both projects' - 'PRIVATE' | 'PRIVATE' | 'PRIVATE' | :guest | 'returning no project' - 'PRIVATE' | 'PRIVATE' | 'PRIVATE' | :anonymous | 'returning no project' + context 'with a user' do + let_it_be(:user) { create(:user) } + + where(:group_visibility, :subgroup_visibility, :project2_visibility, :user_role, :shared_example_name) do + 'PUBLIC' | 'PUBLIC' | 'PUBLIC' | :maintainer | 'returning both projects' + 'PUBLIC' | 'PUBLIC' | 'PUBLIC' | :developer | 'returning both projects' + 'PUBLIC' | 'PUBLIC' | 'PUBLIC' | :guest | 'returning both projects' + 'PUBLIC' | 'PUBLIC' | 'PUBLIC' | :anonymous | 'returning both projects' + 'PUBLIC' | 'PUBLIC' | 'PRIVATE' | :maintainer | 'returning both projects' + 'PUBLIC' | 'PUBLIC' | 'PRIVATE' | :developer | 'returning both projects' + 'PUBLIC' | 'PUBLIC' | 'PRIVATE' | :guest | 'returning project1' + 'PUBLIC' | 'PUBLIC' | 'PRIVATE' | :anonymous | 'returning project1' + 'PUBLIC' | 'PRIVATE' | 'PRIVATE' | :maintainer | 'returning both projects' + 'PUBLIC' | 'PRIVATE' | 'PRIVATE' | :developer | 'returning both projects' + 'PUBLIC' | 'PRIVATE' | 'PRIVATE' | :guest | 'returning project1' + 'PUBLIC' | 'PRIVATE' | 'PRIVATE' | :anonymous | 'returning project1' + 'PRIVATE' | 'PRIVATE' | 'PRIVATE' | :maintainer | 'returning both projects' + 'PRIVATE' | 'PRIVATE' | 'PRIVATE' | :developer | 'returning both projects' + 'PRIVATE' | 'PRIVATE' | 'PRIVATE' | :guest | 'returning no project' + 'PRIVATE' | 'PRIVATE' | 'PRIVATE' | :anonymous | 'returning no project' + end + + with_them do + before do + unless user_role == :anonymous + group.send("add_#{user_role}", user) + subgroup.send("add_#{user_role}", user) + project1.send("add_#{user_role}", user) + project2.send("add_#{user_role}", user) + end + + project2.update!(visibility_level: Gitlab::VisibilityLevel.const_get(project2_visibility, false)) + subgroup.update!(visibility_level: Gitlab::VisibilityLevel.const_get(subgroup_visibility, false)) + project1.update!(visibility_level: Gitlab::VisibilityLevel.const_get(group_visibility, false)) + group.update!(visibility_level: Gitlab::VisibilityLevel.const_get(group_visibility, false)) + end + + it_behaves_like params[:shared_example_name] + end end - with_them do - before do - unless user_role == :anonymous - group.send("add_#{user_role}", user) - subgroup.send("add_#{user_role}", user) - project1.send("add_#{user_role}", user) - project2.send("add_#{user_role}", user) + context 'with a group deploy token' do + let_it_be(:user) { create(:deploy_token, :group, read_package_registry: true) } + let_it_be(:group_deploy_token) { create(:group_deploy_token, deploy_token: user, group: group) } + + shared_examples 'handling all conditions' do + where(:group_visibility, :subgroup_visibility, :project2_visibility, :shared_example_name) do + 'PUBLIC' | 'PUBLIC' | 'PUBLIC' | 'returning both projects' + 'PUBLIC' | 'PUBLIC' | 'PRIVATE' | 'returning both projects' + 'PUBLIC' | 'PRIVATE' | 'PRIVATE' | 'returning both projects' + 'PRIVATE' | 'PRIVATE' | 'PRIVATE' | 'returning both projects' end - project2.update!(visibility_level: Gitlab::VisibilityLevel.const_get(project2_visibility, false)) - subgroup.update!(visibility_level: Gitlab::VisibilityLevel.const_get(subgroup_visibility, false)) - project1.update!(visibility_level: Gitlab::VisibilityLevel.const_get(group_visibility, false)) - group.update!(visibility_level: Gitlab::VisibilityLevel.const_get(group_visibility, false)) + with_them do + before do + project2.update!(visibility_level: Gitlab::VisibilityLevel.const_get(project2_visibility, false)) + subgroup.update!(visibility_level: Gitlab::VisibilityLevel.const_get(subgroup_visibility, false)) + project1.update!(visibility_level: Gitlab::VisibilityLevel.const_get(group_visibility, false)) + group.update!(visibility_level: Gitlab::VisibilityLevel.const_get(group_visibility, false)) + end + + it_behaves_like params[:shared_example_name] + end end - it_behaves_like params[:shared_example_name] + context 'with packages_finder_helper_deploy_token enabled' do + before do + expect(group).not_to receive(:all_projects) + end + + it_behaves_like 'handling all conditions' + end + + context 'with packages_finder_helper_deploy_token disabled' do + before do + stub_feature_flags(packages_finder_helper_deploy_token: false) + expect(group).to receive(:all_projects).and_call_original + end + + it_behaves_like 'handling all conditions' + end end end end