Commit 0139b409 authored by Nick Thomas's avatar Nick Thomas

Merge branch '12250-fix-permissions-for-dependency-list' into 'master'

Access to Dependency List page

Closes #12250

See merge request gitlab-org/gitlab-ee!15044
parents 545b4ca7 4fb147ec
...@@ -3,8 +3,8 @@ ...@@ -3,8 +3,8 @@
module Projects module Projects
module Security module Security
class DependenciesController < Projects::ApplicationController class DependenciesController < Projects::ApplicationController
before_action :authorize_read_dependency_list!
before_action :ensure_dependency_list_feature_available before_action :ensure_dependency_list_feature_available
before_action :authorize_read_dependency_list!
def index def index
respond_to do |format| respond_to do |format|
...@@ -33,7 +33,7 @@ module Projects ...@@ -33,7 +33,7 @@ module Projects
end end
def authorize_read_dependency_list! def authorize_read_dependency_list!
return render_403 unless can?(current_user, :read_project_security_dashboard, project) render_403 unless can?(current_user, :read_dependencies, project)
end end
def ensure_dependency_list_feature_available def ensure_dependency_list_feature_available
...@@ -61,7 +61,7 @@ module Projects ...@@ -61,7 +61,7 @@ module Projects
end end
def serializer def serializer
serializer = ::DependencyListSerializer.new(project: project) serializer = ::DependencyListSerializer.new(project: project, user: current_user)
serializer = serializer.with_pagination(request, response) if params[:page] serializer = serializer.with_pagination(request, response) if params[:page]
serializer serializer
end end
......
# frozen_string_literal: true # frozen_string_literal: true
class DependencyEntity < Grape::Entity class DependencyEntity < Grape::Entity
include RequestAwareEntity
class LocationEntity < Grape::Entity class LocationEntity < Grape::Entity
expose :blob_path, :path expose :blob_path, :path
end end
...@@ -11,5 +13,11 @@ class DependencyEntity < Grape::Entity ...@@ -11,5 +13,11 @@ class DependencyEntity < Grape::Entity
expose :name, :packager, :version expose :name, :packager, :version
expose :location, using: LocationEntity expose :location, using: LocationEntity
expose :vulnerabilities, using: VulnerabilityEntity expose :vulnerabilities, using: VulnerabilityEntity, if: ->(_) { can_read_vulnerabilities? }
private
def can_read_vulnerabilities?
can?(request.user, :read_project_security_dashboard, request.project)
end
end end
...@@ -11,13 +11,17 @@ class DependencyListEntity < Grape::Entity ...@@ -11,13 +11,17 @@ class DependencyListEntity < Grape::Entity
status(list[:dependencies], options[:build]) status(list[:dependencies], options[:build])
end end
expose :job_path, if: ->(_, options) { options[:build] } do |_, options| expose :job_path, if: ->(_, options) { options[:build] && can_read_job_path? } do |_, options|
project_build_path(project, options[:build].id) project_build_path(project, options[:build].id)
end end
end end
private private
def can_read_job_path?
can?(request.user, :read_pipeline, project)
end
def project def project
request.project request.project
end end
......
---
title: Update permissions for Dependency List
merge_request: 15044
author:
type: changed
...@@ -4,7 +4,7 @@ require 'spec_helper' ...@@ -4,7 +4,7 @@ require 'spec_helper'
describe Projects::Security::DependenciesController do describe Projects::Security::DependenciesController do
describe 'GET index.json' do describe 'GET index.json' do
set(:project) { create(:project, :repository, :public) } set(:project) { create(:project, :repository, :private) }
set(:user) { create(:user) } set(:user) { create(:user) }
let(:params) { { namespace_id: project.namespace, project_id: project } } let(:params) { { namespace_id: project.namespace, project_id: project } }
...@@ -19,7 +19,7 @@ describe Projects::Security::DependenciesController do ...@@ -19,7 +19,7 @@ describe Projects::Security::DependenciesController do
context 'when feature is available' do context 'when feature is available' do
before do before do
stub_licensed_features(dependency_list: true, security_dashboard: true) stub_licensed_features(dependency_list: true)
end end
it 'counts usage of the feature' do it 'counts usage of the feature' do
...@@ -167,8 +167,6 @@ describe Projects::Security::DependenciesController do ...@@ -167,8 +167,6 @@ describe Projects::Security::DependenciesController do
context 'when feature is not available' do context 'when feature is not available' do
before do before do
stub_licensed_features(security_dashboard: true)
get :index, params: params, format: :json get :index, params: params, format: :json
end end
...@@ -181,6 +179,7 @@ describe Projects::Security::DependenciesController do ...@@ -181,6 +179,7 @@ describe Projects::Security::DependenciesController do
context 'with unauthorized user' do context 'with unauthorized user' do
before do before do
project.add_guest(user) project.add_guest(user)
stub_licensed_features(dependency_list: true)
get :index, params: params, format: :json get :index, params: params, format: :json
end end
......
...@@ -4,7 +4,14 @@ require 'spec_helper' ...@@ -4,7 +4,14 @@ require 'spec_helper'
describe DependencyEntity do describe DependencyEntity do
describe '#as_json' do describe '#as_json' do
let(:dependency) do subject { described_class.represent(dependency, request: request).as_json }
set(:project) { create(:project, :repository, :private) }
set(:user) { create(:user) }
let(:request) { double('request') }
let(:dependency) { dependency_info.merge(vulnerabilities) }
let(:dependency_info) do
{ {
name: 'nokogiri', name: 'nokogiri',
packager: 'Ruby (Bundler)', packager: 'Ruby (Bundler)',
...@@ -12,7 +19,12 @@ describe DependencyEntity do ...@@ -12,7 +19,12 @@ describe DependencyEntity do
location: { location: {
blob_path: '/some_project/path/Gemfile.lock', blob_path: '/some_project/path/Gemfile.lock',
path: 'Gemfile.lock' path: 'Gemfile.lock'
}, }
}
end
let(:vulnerabilities) do
{
vulnerabilities: vulnerabilities:
[{ [{
name: 'DDoS', name: 'DDoS',
...@@ -25,8 +37,28 @@ describe DependencyEntity do ...@@ -25,8 +37,28 @@ describe DependencyEntity do
} }
end end
subject { described_class.represent(dependency).as_json } before do
stub_licensed_features(security_dashboard: true)
allow(request).to receive(:project).and_return(project)
allow(request).to receive(:user).and_return(user)
end
it { is_expected.to eq(dependency) } context 'with developer' do
before do
project.add_developer(user)
end
it do
is_expected.to eq(dependency)
end
end
context 'with reporter' do
before do
project.add_reporter(user)
end
it { is_expected.to eq(dependency_info) }
end
end end
end end
...@@ -9,15 +9,19 @@ describe DependencyListEntity do ...@@ -9,15 +9,19 @@ describe DependencyListEntity do
end end
let(:request) { double('request') } let(:request) { double('request') }
let(:project) { create(:project) } set(:project) { create(:project, :repository, :private) }
set(:developer) { create(:user) }
subject { entity.as_json } subject { entity.as_json }
before do before do
project.add_developer(developer)
allow(request).to receive(:project).and_return(project) allow(request).to receive(:project).and_return(project)
allow(request).to receive(:user).and_return(user)
end end
context 'with success build' do context 'with success build' do
let(:user) { developer }
let(:build) { create(:ee_ci_build, :success) } let(:build) { create(:ee_ci_build, :success) }
context 'with provided dependencies' do context 'with provided dependencies' do
...@@ -43,6 +47,7 @@ describe DependencyListEntity do ...@@ -43,6 +47,7 @@ describe DependencyListEntity do
end end
context 'with no dependencies' do context 'with no dependencies' do
let(:user) { developer }
let(:dependencies) { [] } let(:dependencies) { [] }
it 'has empty array of dependencies with status no_dependencies' do it 'has empty array of dependencies with status no_dependencies' do
...@@ -59,19 +64,33 @@ describe DependencyListEntity do ...@@ -59,19 +64,33 @@ describe DependencyListEntity do
let(:build) { create(:ee_ci_build, :failed) } let(:build) { create(:ee_ci_build, :failed) }
let(:dependencies) { [] } let(:dependencies) { [] }
context 'with authorized user' do
let(:user) { developer }
it 'has job_path with status failed_job' do it 'has job_path with status failed_job' do
expect(subject[:report][:status]).to eq(:job_failed) expect(subject[:report][:status]).to eq(:job_failed)
expect(subject[:report]).to include(:job_path) expect(subject[:report]).to include(:job_path)
end end
end end
context 'without authorized user' do
let(:user) { create(:user) }
it 'has only status failed_job' do
expect(subject[:report][:status]).to eq(:job_failed)
expect(subject[:report]).not_to include(:job_path)
end
end
end
context 'with no build' do context 'with no build' do
let(:user) { developer }
let(:build) { nil } let(:build) { nil }
let(:dependencies) { [] } let(:dependencies) { [] }
it 'has status job_not_set_up and no job_path' do it 'has status job_not_set_up and no job_path' do
expect(subject[:report][:status]).to eq(:job_not_set_up) expect(subject[:report][:status]).to eq(:job_not_set_up)
expect(subject[:report]).not_to include(:job_path) expect(subject[:report][:job_path]).not_to be_present
end end
end end
end end
......
...@@ -3,9 +3,13 @@ ...@@ -3,9 +3,13 @@
require 'spec_helper' require 'spec_helper'
describe DependencyListSerializer do describe DependencyListSerializer do
let(:serializer) { described_class.new(project: project).represent(dependencies, build: build) }
let(:build) { create(:ee_ci_build, :success) } let(:build) { create(:ee_ci_build, :success) }
let(:project) { create(:project) } set(:project) { create(:project, :repository, :private) }
set(:user) { create(:user) }
let(:serializer) do
described_class.new(project: project, user: user).represent(dependencies, build: build)
end
let(:dependencies) do let(:dependencies) do
[{ [{
...@@ -24,6 +28,11 @@ describe DependencyListSerializer do ...@@ -24,6 +28,11 @@ describe DependencyListSerializer do
}] }]
end end
before do
stub_licensed_features(security_dashboard: true)
project.add_developer(user)
end
describe "#to_json" do describe "#to_json" do
subject { serializer.to_json } subject { serializer.to_json }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment