Commit 9f67451c authored by Alan (Maciej) Paruszewski's avatar Alan (Maciej) Paruszewski Committed by charlie ablett

Add query for projects selected for instance security dashboard

Add ability in GraphQL API to query projects added in Instance Security
Dashboard.
parent 0770ce89
......@@ -4319,6 +4319,33 @@ enum HealthStatus {
onTrack
}
type InstanceSecurityDashboard {
"""
Projects selected in Instance Security Dashboard
"""
projects(
"""
Returns the elements in the list that come after the specified cursor.
"""
after: String
"""
Returns the elements in the list that come before the specified cursor.
"""
before: String
"""
Returns the first _n_ elements from the list.
"""
first: Int
"""
Returns the last _n_ elements from the list.
"""
last: Int
): ProjectConnection!
}
"""
State of a GitLab issue or merge request
"""
......@@ -8021,6 +8048,11 @@ type Query {
fullPath: ID!
): Group
"""
Fields related to Instance Security Dashboard
"""
instanceSecurityDashboard: InstanceSecurityDashboard
"""
Metadata about GitLab
"""
......
......@@ -12025,6 +12025,76 @@
"enumValues": null,
"possibleTypes": null
},
{
"kind": "OBJECT",
"name": "InstanceSecurityDashboard",
"description": null,
"fields": [
{
"name": "projects",
"description": "Projects selected in Instance Security Dashboard",
"args": [
{
"name": "after",
"description": "Returns the elements in the list that come after the specified cursor.",
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"defaultValue": null
},
{
"name": "before",
"description": "Returns the elements in the list that come before the specified cursor.",
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"defaultValue": null
},
{
"name": "first",
"description": "Returns the first _n_ elements from the list.",
"type": {
"kind": "SCALAR",
"name": "Int",
"ofType": null
},
"defaultValue": null
},
{
"name": "last",
"description": "Returns the last _n_ elements from the list.",
"type": {
"kind": "SCALAR",
"name": "Int",
"ofType": null
},
"defaultValue": null
}
],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "OBJECT",
"name": "ProjectConnection",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
}
],
"inputFields": null,
"interfaces": [
],
"enumValues": null,
"possibleTypes": null
},
{
"kind": "SCALAR",
"name": "Int",
......@@ -23715,6 +23785,20 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "instanceSecurityDashboard",
"description": "Fields related to Instance Security Dashboard",
"args": [
],
"type": {
"kind": "OBJECT",
"name": "InstanceSecurityDashboard",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "metadata",
"description": "Metadata about GitLab",
......
......@@ -18,7 +18,7 @@ module EE
mount_mutation ::Mutations::Requirements::Update
mount_mutation ::Mutations::Vulnerabilities::Dismiss
mount_mutation ::Mutations::Boards::Lists::UpdateLimitMetrics
mount_mutation ::Mutations::SecurityDashboard::AddProject
mount_mutation ::Mutations::InstanceSecurityDashboard::AddProject
end
end
end
......
......@@ -24,6 +24,11 @@ module EE
resolver: Resolvers::Geo::GeoNodeResolver,
description: 'Find a Geo node'
field :instance_security_dashboard, ::Types::InstanceSecurityDashboardType,
null: true,
resolver: Resolvers::InstanceSecurityDashboardResolver,
description: 'Fields related to Instance Security Dashboard'
def design_management
DesignManagementObject.new(nil)
end
......
# frozen_string_literal: true
module Mutations
module SecurityDashboard
module InstanceSecurityDashboard
class AddProject < BaseMutation
graphql_name 'AddProjectToSecurityDashboard'
......
# frozen_string_literal: true
module Resolvers
module InstanceSecurityDashboard
class ProjectsResolver < BaseResolver
type ::Types::ProjectType, null: true
alias_method :dashboard, :object
def resolve(**args)
dashboard&.projects
end
end
end
end
# frozen_string_literal: true
module Resolvers
class InstanceSecurityDashboardResolver < BaseResolver
type ::Types::InstanceSecurityDashboardType, null: true
def resolve(**args)
::InstanceSecurityDashboard.new(current_user)
end
end
end
......@@ -38,7 +38,7 @@ module Resolvers
strong_memoize(:vulnerable) do
if resolve_vulnerabilities_for_instance_security_dashboard?
InstanceSecurityDashboard.new(current_user)
::InstanceSecurityDashboard.new(current_user)
elsif object.respond_to?(:sync)
object.sync
else
......
# frozen_string_literal: true
module Types
class InstanceSecurityDashboardType < BaseObject
graphql_name 'InstanceSecurityDashboard'
authorize :read_instance_security_dashboard
field :projects,
Types::ProjectType.connection_type,
null: false,
authorize: :read_project,
description: 'Projects selected in Instance Security Dashboard'
end
end
---
title: Add GraphQL query for Instance Security Dashboard projects
merge_request: 30064
author:
type: added
# frozen_string_literal: true
require 'spec_helper'
describe Mutations::SecurityDashboard::AddProject do
describe Mutations::InstanceSecurityDashboard::AddProject do
let(:mutation) { described_class.new(object: nil, context: { current_user: current_user }, field: nil) }
describe '#resolve' do
......
# frozen_string_literal: true
require 'spec_helper'
describe Resolvers::InstanceSecurityDashboard::ProjectsResolver do
include GraphqlHelpers
describe '#resolve' do
subject { resolve(described_class, obj: object, ctx: { current_user: user }) }
let_it_be(:project) { create(:project) }
let_it_be(:user) { create(:user, security_dashboard_projects: [project]) }
context 'when provided object is InstanceSecurityDashboard' do
let(:object) { InstanceSecurityDashboard.new(user) }
it { is_expected.to eq(object.projects) }
end
context 'when object is not provided' do
let(:object) { nil }
it { is_expected.to be_nil }
end
end
end
# frozen_string_literal: true
require 'spec_helper'
describe Resolvers::InstanceSecurityDashboardResolver do
include GraphqlHelpers
describe '#resolve' do
subject(:instance_security_dashboard) { resolve(described_class, ctx: { current_user: current_user }) }
let_it_be(:current_user) { create(:user) }
it { is_expected.to be_a(InstanceSecurityDashboard) }
end
end
# frozen_string_literal: true
require 'spec_helper'
describe GitlabSchema.types['InstanceSecurityDashboard'] do
let_it_be(:project) { create(:project) }
let_it_be(:other_project) { create(:project) }
let_it_be(:user) { create(:user, security_dashboard_projects: [project]) }
let(:fields) do
%i[projects]
end
before do
project.add_developer(user)
other_project.add_developer(user)
stub_licensed_features(security_dashboard: true)
end
let(:result) { GitlabSchema.execute(query, context: { current_user: current_user }).as_json }
specify { expect(described_class).to have_graphql_fields(fields) }
describe 'projects' do
let(:query) do
%(
query {
instanceSecurityDashboard {
projects {
nodes {
id
}
}
}
}
)
end
subject(:projects) { result.dig('data', 'instanceSecurityDashboard', 'projects') }
context 'when user is not logged in' do
let(:current_user) { nil }
it { is_expected.to be_nil }
end
context 'when user is logged in' do
let(:current_user) { user }
it 'is a list of projects configured for instance security dashboard' do
project_ids = projects['nodes'].pluck('id')
expect(project_ids).to eq [GitlabSchema.id_from_object(project).to_s]
end
end
end
end
......@@ -7,7 +7,8 @@ describe GitlabSchema.types['Query'] do
expect(described_class).to have_graphql_fields(
:design_management,
:geo_node,
:vulnerabilities
:vulnerabilities,
:instance_security_dashboard
).at_least
end
end
# frozen_string_literal: true
require 'spec_helper'
describe 'Query.instanceSecurityDashboard.projects' do
include GraphqlHelpers
let_it_be(:project) { create(:project) }
let_it_be(:other_project) { create(:project) }
let_it_be(:user) { create(:user, security_dashboard_projects: [project]) }
let(:current_user) { user }
before do
project.add_developer(user)
other_project.add_developer(user)
stub_licensed_features(security_dashboard: true)
end
let(:fields) do
<<~QUERY
nodes {
id
}
QUERY
end
let(:query) do
graphql_query_for('instanceSecurityDashboard', nil, query_graphql_field('projects', {}, fields))
end
subject(:projects) { graphql_data.dig('instanceSecurityDashboard', 'projects', 'nodes') }
context 'with logged in user' do
it_behaves_like 'a working graphql query' do
before do
post_graphql(query, current_user: current_user)
end
it 'finds only projects that were added to instance security dashboard' do
expect(projects).to eq([{ "id" => GitlabSchema.id_from_object(project).to_s }])
end
end
end
context 'with no user' do
let(:current_user) { nil }
it_behaves_like 'a working graphql query' do
before do
post_graphql(query, current_user: current_user)
end
it { is_expected.to be_nil }
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