Commit ce087b3b authored by Mehmet Emin INAC's avatar Mehmet Emin INAC Committed by GitLab Release Tools Bot

Authorize users to read security related pipeline fields

parent d2e8fb82
...@@ -2,13 +2,17 @@ ...@@ -2,13 +2,17 @@
module Resolvers module Resolvers
class SecurityReportSummaryResolver < BaseResolver class SecurityReportSummaryResolver < BaseResolver
type Types::SecurityReportSummaryType, null: true include Gitlab::Graphql::Authorize::AuthorizeResource
type Types::SecurityReportSummaryType, null: true
authorize :read_security_resource
extras [:lookahead] extras [:lookahead]
alias_method :pipeline, :object alias_method :pipeline, :object
def resolve(lookahead:) def resolve(lookahead:)
return unless authorized_resource?(pipeline.project)
Security::ReportSummaryService.new( Security::ReportSummaryService.new(
pipeline, pipeline,
selection_information(lookahead) selection_information(lookahead)
......
# frozen_string_literal: true # frozen_string_literal: true
module Types module Types
# rubocop: disable Graphql/AuthorizeTypes
class PipelineSecurityReportFindingType < BaseObject class PipelineSecurityReportFindingType < BaseObject
graphql_name 'PipelineSecurityReportFinding' graphql_name 'PipelineSecurityReportFinding'
description 'Represents vulnerability finding of a security report on the pipeline.' description 'Represents vulnerability finding of a security report on the pipeline.'
authorize :read_security_resource
field :report_type, field :report_type,
type: VulnerabilityReportTypeEnum, type: VulnerabilityReportTypeEnum,
null: true, null: true,
...@@ -97,5 +98,4 @@ module Types ...@@ -97,5 +98,4 @@ module Types
object.project.licensed_feature_available?(:sast_fp_reduction) object.project.licensed_feature_available?(:sast_fp_reduction)
end end
end end
# rubocop: enable Graphql/AuthorizeTypes
end end
...@@ -106,6 +106,8 @@ module Vulnerabilities ...@@ -106,6 +106,8 @@ module Vulnerabilities
.where("vulnerability_occurrences.location -> 'cluster_id' ?| array[:cluster_ids]", cluster_ids: cluster_ids) .where("vulnerability_occurrences.location -> 'cluster_id' ?| array[:cluster_ids]", cluster_ids: cluster_ids)
end end
alias_method :declarative_policy_subject, :project
def self.counted_by_severity def self.counted_by_severity
group(:severity).count.transform_keys do |severity| group(:severity).count.transform_keys do |severity|
severities[severity] severities[severity]
......
...@@ -5,9 +5,14 @@ require 'spec_helper' ...@@ -5,9 +5,14 @@ require 'spec_helper'
RSpec.describe Resolvers::SecurityReportSummaryResolver do RSpec.describe Resolvers::SecurityReportSummaryResolver do
include GraphqlHelpers include GraphqlHelpers
let_it_be(:pipeline) { 'pipeline' } let_it_be(:pipeline) { create(:ci_pipeline) }
let_it_be(:user) { pipeline.project.owner }
describe '#resolve' do describe '#resolve' do
before do
stub_licensed_features(sast: true, dependency_scanning: true, container_scanning: true, dast: true, security_dashboard: true)
end
context 'All fields are requested' do context 'All fields are requested' do
let(:lookahead) do let(:lookahead) do
build_mock_lookahead(expected_selection_info) build_mock_lookahead(expected_selection_info)
...@@ -32,7 +37,18 @@ RSpec.describe Resolvers::SecurityReportSummaryResolver do ...@@ -32,7 +37,18 @@ RSpec.describe Resolvers::SecurityReportSummaryResolver do
) do |summary_service| ) do |summary_service|
expect(summary_service).to receive(:execute).and_return({}) expect(summary_service).to receive(:execute).and_return({})
end end
resolve(described_class, obj: pipeline, lookahead: lookahead)
resolve_security_report_summary
end
context 'when the user is not authorized' do
let_it_be(:user) { create(:user) }
it 'does not call Security::ReportSummaryService and returns nothing' do
stub_const('Security::ReportSummaryService', double)
expect(resolve_security_report_summary).to be_nil
end
end end
end end
...@@ -61,10 +77,15 @@ RSpec.describe Resolvers::SecurityReportSummaryResolver do ...@@ -61,10 +77,15 @@ RSpec.describe Resolvers::SecurityReportSummaryResolver do
) do |summary_service| ) do |summary_service|
expect(summary_service).to receive(:execute).and_return({}) expect(summary_service).to receive(:execute).and_return({})
end end
resolve(described_class, obj: pipeline, lookahead: lookahead)
resolve_security_report_summary
end end
end end
end end
def resolve_security_report_summary
resolve(described_class, obj: pipeline, lookahead: lookahead, ctx: { current_user: user })
end
end end
def build_mock_lookahead(structure) def build_mock_lookahead(structure)
......
...@@ -33,6 +33,7 @@ RSpec.describe GitlabSchema.types['PipelineSecurityReportFinding'] do ...@@ -33,6 +33,7 @@ RSpec.describe GitlabSchema.types['PipelineSecurityReportFinding'] do
subject { GitlabSchema.execute(query, context: { current_user: user }).as_json } subject { GitlabSchema.execute(query, context: { current_user: user }).as_json }
specify { expect(described_class.graphql_name).to eq('PipelineSecurityReportFinding') } specify { expect(described_class.graphql_name).to eq('PipelineSecurityReportFinding') }
specify { expect(described_class).to require_graphql_authorizations(:read_security_resource) }
it { expect(described_class).to have_graphql_fields(fields) } it { expect(described_class).to have_graphql_fields(fields) }
......
...@@ -3,7 +3,9 @@ ...@@ -3,7 +3,9 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe 'Query.project(fullPath).pipeline(iid).securityReportFindings' do RSpec.describe 'Query.project(fullPath).pipeline(iid).securityReportFindings' do
let_it_be(:project) { create(:project, :repository) } include GraphqlHelpers
let_it_be(:project) { create(:project, :repository, :public) }
let_it_be(:pipeline) { create(:ci_pipeline, :success, project: project) } let_it_be(:pipeline) { create(:ci_pipeline, :success, project: project) }
let_it_be(:user) { create(:user) } let_it_be(:user) { create(:user) }
...@@ -49,13 +51,16 @@ RSpec.describe 'Query.project(fullPath).pipeline(iid).securityReportFindings' do ...@@ -49,13 +51,16 @@ RSpec.describe 'Query.project(fullPath).pipeline(iid).securityReportFindings' do
) )
end end
subject { GitlabSchema.execute(query, context: { current_user: user }).as_json } let(:security_report_findings) { subject.dig('project', 'pipeline', 'securityReportFindings', 'nodes') }
let(:security_report_findings) { subject.dig('data', 'project', 'pipeline', 'securityReportFindings', 'nodes') } subject do
post_graphql(query, current_user: user)
graphql_data
end
context 'when `sast` and `dast` features are enabled' do context 'when the required features are enabled' do
before do before do
stub_licensed_features(sast: true, dast: true) stub_licensed_features(sast: true, dast: true, security_dashboard: true)
end end
context 'when user is member of the project' do context 'when user is member of the project' do
...@@ -86,18 +91,18 @@ RSpec.describe 'Query.project(fullPath).pipeline(iid).securityReportFindings' do ...@@ -86,18 +91,18 @@ RSpec.describe 'Query.project(fullPath).pipeline(iid).securityReportFindings' do
context 'when user is not a member of the project' do context 'when user is not a member of the project' do
it 'returns no vulnerability findings' do it 'returns no vulnerability findings' do
expect(security_report_findings).to be_nil expect(security_report_findings).to be_blank
end end
end end
end end
context 'when `sast` and `dast` both features are disabled' do context 'when the required features are disabled' do
before do before do
stub_licensed_features(sast: false, dast: false) stub_licensed_features(sast: false, dast: false, security_dashboard: false)
end end
it 'returns no vulnerability findings' do it 'returns no vulnerability findings' do
expect(security_report_findings).to be_nil expect(security_report_findings).to be_blank
end end
end end
end end
...@@ -3,6 +3,8 @@ ...@@ -3,6 +3,8 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe 'Query.project(fullPath).pipeline(iid).securityReportSummary' do RSpec.describe 'Query.project(fullPath).pipeline(iid).securityReportSummary' do
include GraphqlHelpers
let_it_be(:project) { create(:project, :repository) } let_it_be(:project) { create(:project, :repository) }
let_it_be(:pipeline) { create(:ci_pipeline, :success, project: project) } let_it_be(:pipeline) { create(:ci_pipeline, :success, project: project) }
...@@ -66,28 +68,54 @@ RSpec.describe 'Query.project(fullPath).pipeline(iid).securityReportSummary' do ...@@ -66,28 +68,54 @@ RSpec.describe 'Query.project(fullPath).pipeline(iid).securityReportSummary' do
) )
end end
before do let(:security_report_summary) { subject.dig('project', 'pipeline', 'securityReportSummary') }
stub_licensed_features(sast: true, dependency_scanning: true, container_scanning: true, dast: true)
project.add_developer(user) subject do
post_graphql(query, current_user: user)
graphql_data
end end
subject { GitlabSchema.execute(query, context: { current_user: user }).as_json } context 'when the required features are enabled' do
before do
stub_licensed_features(sast: true, dependency_scanning: true, container_scanning: true, dast: true, security_dashboard: true)
end
context 'when user is member of the project' do
before do
project.add_developer(user)
end
it 'shows the vulnerabilitiesCount and scannedResourcesCount' do
expect(security_report_summary.dig('dast', 'vulnerabilitiesCount')).to eq(20)
expect(security_report_summary.dig('dast', 'scannedResourcesCount')).to eq(26)
expect(security_report_summary.dig('sast', 'vulnerabilitiesCount')).to eq(5)
end
let(:security_report_summary) { subject.dig('data', 'project', 'pipeline', 'securityReportSummary') } it 'shows the first 20 scanned resources' do
dast_scanned_resources = security_report_summary.dig('dast', 'scannedResources', 'nodes')
it 'shows the vulnerabilitiesCount and scannedResourcesCount' do expect(dast_scanned_resources.length).to eq(20)
expect(security_report_summary.dig('dast', 'vulnerabilitiesCount')).to eq(20) end
expect(security_report_summary.dig('dast', 'scannedResourcesCount')).to eq(26)
expect(security_report_summary.dig('sast', 'vulnerabilitiesCount')).to eq(5)
end
it 'shows the first 20 scanned resources' do it 'returns nil for the scannedResourcesCsvPath' do
dast_scanned_resources = security_report_summary.dig('dast', 'scannedResources', 'nodes') expect(security_report_summary.dig('dast', 'scannedResourcesCsvPath')).to be_nil
end
end
expect(dast_scanned_resources.length).to eq(20) context 'when user is not a member of the project' do
it 'returns no scanned resources' do
expect(security_report_summary).to be_nil
end
end
end end
it 'returns nil for the scannedResourcesCsvPath' do context 'when the required features are disabled' do
expect(security_report_summary.dig('dast', 'scannedResourcesCsvPath')).to be_nil before do
stub_licensed_features(sast: false, dependency_scanning: false, container_scanning: false, dast: false, security_dashboard: false)
end
it 'returns no scanned resources' do
expect(security_report_summary).to be_nil
end
end end
end end
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