Commit e61fe76c authored by Alan (Maciej) Paruszewski's avatar Alan (Maciej) Paruszewski Committed by Imre Farkas

Add mutation to Confirm Vulnerability in GraphQL

This change adds new mutation that allows user to confirm vulnerability
using GraphQL API.
parent 06c6774a
...@@ -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
vulnerabilityConfirm(input: VulnerabilityConfirmInput!): VulnerabilityConfirmPayload
vulnerabilityResolve(input: VulnerabilityResolveInput!): VulnerabilityResolvePayload vulnerabilityResolve(input: VulnerabilityResolveInput!): VulnerabilityResolvePayload
} }
...@@ -18780,6 +18781,41 @@ type Vulnerability { ...@@ -18780,6 +18781,41 @@ type Vulnerability {
vulnerabilityPath: String vulnerabilityPath: String
} }
"""
Autogenerated input type of VulnerabilityConfirm
"""
input VulnerabilityConfirmInput {
"""
A unique identifier for the client performing the mutation.
"""
clientMutationId: String
"""
ID of the vulnerability to be confirmed
"""
id: VulnerabilityID!
}
"""
Autogenerated return type of VulnerabilityConfirm
"""
type VulnerabilityConfirmPayload {
"""
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
}
""" """
The connection type for Vulnerability. The connection type for Vulnerability.
""" """
......
...@@ -32407,6 +32407,33 @@ ...@@ -32407,6 +32407,33 @@
"isDeprecated": false, "isDeprecated": false,
"deprecationReason": null "deprecationReason": null
}, },
{
"name": "vulnerabilityConfirm",
"description": null,
"args": [
{
"name": "input",
"description": null,
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "INPUT_OBJECT",
"name": "VulnerabilityConfirmInput",
"ofType": null
}
},
"defaultValue": null
}
],
"type": {
"kind": "OBJECT",
"name": "VulnerabilityConfirmPayload",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{ {
"name": "vulnerabilityResolve", "name": "vulnerabilityResolve",
"description": null, "description": null,
...@@ -54904,6 +54931,108 @@ ...@@ -54904,6 +54931,108 @@
"enumValues": null, "enumValues": null,
"possibleTypes": null "possibleTypes": null
}, },
{
"kind": "INPUT_OBJECT",
"name": "VulnerabilityConfirmInput",
"description": "Autogenerated input type of VulnerabilityConfirm",
"fields": null,
"inputFields": [
{
"name": "id",
"description": "ID of the vulnerability to be confirmed",
"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": "VulnerabilityConfirmPayload",
"description": "Autogenerated return type of VulnerabilityConfirm",
"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": "VulnerabilityConnection", "name": "VulnerabilityConnection",
...@@ -2700,6 +2700,16 @@ Represents a vulnerability. ...@@ -2700,6 +2700,16 @@ Represents a vulnerability.
| `userPermissions` | VulnerabilityPermissions! | Permissions for the current user on the resource | | `userPermissions` | VulnerabilityPermissions! | Permissions for the current user on the resource |
| `vulnerabilityPath` | String | URL to the vulnerability's details page | | `vulnerabilityPath` | String | URL to the vulnerability's details page |
### VulnerabilityConfirmPayload
Autogenerated return type of VulnerabilityConfirm.
| 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 |
### VulnerabilityIdentifier ### VulnerabilityIdentifier
Represents a vulnerability identifier. Represents a vulnerability identifier.
......
...@@ -24,6 +24,7 @@ module EE ...@@ -24,6 +24,7 @@ module EE
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::Vulnerabilities::Resolve
mount_mutation ::Mutations::Vulnerabilities::Confirm
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 Confirm < BaseMutation
graphql_name 'VulnerabilityConfirm'
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 confirmed'
def resolve(id:)
vulnerability = authorized_find!(id: id)
result = confirm_vulnerability(vulnerability)
{
vulnerability: result,
errors: result.errors.full_messages || []
}
end
private
def confirm_vulnerability(vulnerability)
::Vulnerabilities::ConfirmService.new(current_user, vulnerability).execute
end
def find_object(id:)
GitlabSchema.find_by_gid(id)
end
end
end
end
---
title: Add mutation to Confirm Vulnerability in GraphQL
merge_request: 42499
author:
type: added
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Mutations::Vulnerabilities::Confirm 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 confirm 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 Confirmed vulnerability' do
expect(mutated_vulnerability).to eq(vulnerability)
expect(mutated_vulnerability).to be_confirmed
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