Commit ae085beb authored by Heinrich Lee Yu's avatar Heinrich Lee Yu

Merge branch '223812-add-mutation-to-resolve-vulnerability' into 'master'

Add mutation to Resolve Vulnerability in GraphQL

See merge request gitlab-org/gitlab!42500
parents 50eaf781 d4d98166
...@@ -10875,6 +10875,7 @@ type Mutation { ...@@ -10875,6 +10875,7 @@ type Mutation {
updateNote(input: UpdateNoteInput!): UpdateNotePayload updateNote(input: UpdateNoteInput!): UpdateNotePayload
updateRequirement(input: UpdateRequirementInput!): UpdateRequirementPayload updateRequirement(input: UpdateRequirementInput!): UpdateRequirementPayload
updateSnippet(input: UpdateSnippetInput!): UpdateSnippetPayload updateSnippet(input: UpdateSnippetInput!): UpdateSnippetPayload
vulnerabilityResolve(input: VulnerabilityResolveInput!): VulnerabilityResolvePayload
} }
""" """
...@@ -18825,6 +18826,11 @@ enum VulnerabilityGrade { ...@@ -18825,6 +18826,11 @@ enum VulnerabilityGrade {
F F
} }
"""
Identifier of Vulnerability
"""
scalar VulnerabilityID
""" """
Represents a vulnerability identifier Represents a vulnerability identifier
""" """
...@@ -19125,6 +19131,41 @@ enum VulnerabilityReportType { ...@@ -19125,6 +19131,41 @@ enum VulnerabilityReportType {
SECRET_DETECTION SECRET_DETECTION
} }
"""
Autogenerated input type of VulnerabilityResolve
"""
input VulnerabilityResolveInput {
"""
A unique identifier for the client performing the mutation.
"""
clientMutationId: String
"""
ID of the vulnerability to be resolveed
"""
id: VulnerabilityID!
}
"""
Autogenerated return type of VulnerabilityResolve
"""
type VulnerabilityResolvePayload {
"""
A unique identifier for the client performing the mutation.
"""
clientMutationId: String
"""
Errors encountered during execution of the mutation.
"""
errors: [String!]!
"""
The vulnerability after state change
"""
vulnerability: Vulnerability
}
""" """
Represents a vulnerability scanner Represents a vulnerability scanner
""" """
......
...@@ -32406,6 +32406,33 @@ ...@@ -32406,6 +32406,33 @@
}, },
"isDeprecated": false, "isDeprecated": false,
"deprecationReason": null "deprecationReason": null
},
{
"name": "vulnerabilityResolve",
"description": null,
"args": [
{
"name": "input",
"description": null,
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "INPUT_OBJECT",
"name": "VulnerabilityResolveInput",
"ofType": null
}
},
"defaultValue": null
}
],
"type": {
"kind": "OBJECT",
"name": "VulnerabilityResolvePayload",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
} }
], ],
"inputFields": null, "inputFields": null,
...@@ -55030,6 +55057,16 @@ ...@@ -55030,6 +55057,16 @@
], ],
"possibleTypes": null "possibleTypes": null
}, },
{
"kind": "SCALAR",
"name": "VulnerabilityID",
"description": "Identifier of Vulnerability",
"fields": null,
"inputFields": null,
"interfaces": null,
"enumValues": null,
"possibleTypes": null
},
{ {
"kind": "OBJECT", "kind": "OBJECT",
"name": "VulnerabilityIdentifier", "name": "VulnerabilityIdentifier",
...@@ -55960,6 +55997,108 @@ ...@@ -55960,6 +55997,108 @@
], ],
"possibleTypes": null "possibleTypes": null
}, },
{
"kind": "INPUT_OBJECT",
"name": "VulnerabilityResolveInput",
"description": "Autogenerated input type of VulnerabilityResolve",
"fields": null,
"inputFields": [
{
"name": "id",
"description": "ID of the vulnerability to be resolveed",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "VulnerabilityID",
"ofType": null
}
},
"defaultValue": null
},
{
"name": "clientMutationId",
"description": "A unique identifier for the client performing the mutation.",
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"defaultValue": null
}
],
"interfaces": null,
"enumValues": null,
"possibleTypes": null
},
{
"kind": "OBJECT",
"name": "VulnerabilityResolvePayload",
"description": "Autogenerated return type of VulnerabilityResolve",
"fields": [
{
"name": "clientMutationId",
"description": "A unique identifier for the client performing the mutation.",
"args": [
],
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "errors",
"description": "Errors encountered during execution of the mutation.",
"args": [
],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "LIST",
"name": null,
"ofType": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
}
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "vulnerability",
"description": "The vulnerability after state change",
"args": [
],
"type": {
"kind": "OBJECT",
"name": "Vulnerability",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
}
],
"inputFields": null,
"interfaces": [
],
"enumValues": null,
"possibleTypes": null
},
{ {
"kind": "OBJECT", "kind": "OBJECT",
"name": "VulnerabilityScanner", "name": "VulnerabilityScanner",
...@@ -2802,6 +2802,16 @@ Check permissions for the current user on a vulnerability. ...@@ -2802,6 +2802,16 @@ Check permissions for the current user on a vulnerability.
| `readVulnerabilityFeedback` | Boolean! | Indicates the user can perform `read_vulnerability_feedback` on this resource | | `readVulnerabilityFeedback` | Boolean! | Indicates the user can perform `read_vulnerability_feedback` on this resource |
| `updateVulnerabilityFeedback` | Boolean! | Indicates the user can perform `update_vulnerability_feedback` on this resource | | `updateVulnerabilityFeedback` | Boolean! | Indicates the user can perform `update_vulnerability_feedback` on this resource |
### VulnerabilityResolvePayload
Autogenerated return type of VulnerabilityResolve.
| Field | Type | Description |
| ----- | ---- | ----------- |
| `clientMutationId` | String | A unique identifier for the client performing the mutation. |
| `errors` | String! => Array | Errors encountered during execution of the mutation. |
| `vulnerability` | Vulnerability | The vulnerability after state change |
### VulnerabilityScanner ### VulnerabilityScanner
Represents a vulnerability scanner. Represents a vulnerability scanner.
......
...@@ -23,6 +23,7 @@ module EE ...@@ -23,6 +23,7 @@ module EE
mount_mutation ::Mutations::RequirementsManagement::CreateRequirement mount_mutation ::Mutations::RequirementsManagement::CreateRequirement
mount_mutation ::Mutations::RequirementsManagement::UpdateRequirement mount_mutation ::Mutations::RequirementsManagement::UpdateRequirement
mount_mutation ::Mutations::Vulnerabilities::Dismiss mount_mutation ::Mutations::Vulnerabilities::Dismiss
mount_mutation ::Mutations::Vulnerabilities::Resolve
mount_mutation ::Mutations::Boards::Update mount_mutation ::Mutations::Boards::Update
mount_mutation ::Mutations::Boards::Lists::UpdateLimitMetrics mount_mutation ::Mutations::Boards::Lists::UpdateLimitMetrics
mount_mutation ::Mutations::InstanceSecurityDashboard::AddProject mount_mutation ::Mutations::InstanceSecurityDashboard::AddProject
......
# frozen_string_literal: true
module Mutations
module Vulnerabilities
class Resolve < BaseMutation
graphql_name 'VulnerabilityResolve'
authorize :admin_vulnerability
field :vulnerability, Types::VulnerabilityType,
null: true,
description: 'The vulnerability after state change'
argument :id,
::Types::GlobalIDType[::Vulnerability],
required: true,
description: 'ID of the vulnerability to be resolveed'
def resolve(id:)
vulnerability = authorized_find!(id: id)
result = resolve_vulnerability(vulnerability)
{
vulnerability: result,
errors: result.errors.full_messages || []
}
end
private
def resolve_vulnerability(vulnerability)
::Vulnerabilities::ResolveService.new(current_user, vulnerability).execute
end
def find_object(id:)
GitlabSchema.find_by_gid(id)
end
end
end
end
---
title: Add mutation to Resolve Vulnerability in GraphQL
merge_request: 42500
author:
type: added
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Mutations::Vulnerabilities::Resolve do
let(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) }
describe '#resolve' do
let_it_be(:vulnerability) { create(:vulnerability, :with_findings) }
let_it_be(:user) { create(:user) }
let(:mutated_vulnerability) { subject[:vulnerability] }
subject { mutation.resolve(id: GitlabSchema.id_from_object(vulnerability)) }
context 'when the user can resolve the vulnerability' do
before do
stub_licensed_features(security_dashboard: true)
end
context 'when user doe not have access to the project' do
it 'raises an error' do
expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
end
end
context 'when user has access to the project' do
before do
vulnerability.project.add_developer(user)
end
it 'returns the resolveed vulnerability', :aggregate_failures do
expect(mutated_vulnerability).to eq(vulnerability)
expect(mutated_vulnerability).to be_resolved
expect(subject[:errors]).to be_empty
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