Commit 33cc752c authored by Alan (Maciej) Paruszewski's avatar Alan (Maciej) Paruszewski Committed by James Lopez

Add details to Vulnerability GraphQL

This change adds new field to Vulnerability GraphQL API that allows to
fetch additional information about vulnerability.
parent 0859b783
......@@ -25914,6 +25914,11 @@ type Vulnerability implements Noteable {
"""
description: String
"""
Details of the vulnerability
"""
details: [VulnerabilityDetail!]!
"""
Timestamp of when the vulnerability was first detected
"""
......@@ -26182,6 +26187,366 @@ type VulnerabilityConnection {
pageInfo: PageInfo!
}
"""
Represents a vulnerability detail field. The fields with data will depend on the vulnerability detail type
"""
union VulnerabilityDetail = VulnerabilityDetailBase | VulnerabilityDetailBoolean | VulnerabilityDetailCode | VulnerabilityDetailCommit | VulnerabilityDetailDiff | VulnerabilityDetailFileLocation | VulnerabilityDetailInt | VulnerabilityDetailList | VulnerabilityDetailMarkdown | VulnerabilityDetailModuleLocation | VulnerabilityDetailTable | VulnerabilityDetailText | VulnerabilityDetailUrl
"""
Represents the vulnerability details base
"""
type VulnerabilityDetailBase {
"""
Description of the field.
"""
description: String!
"""
Name of the field.
"""
fieldName: String
"""
Name of the field.
"""
name: String!
}
"""
Represents the vulnerability details boolean value
"""
type VulnerabilityDetailBoolean {
"""
Description of the field.
"""
description: String!
"""
Name of the field.
"""
fieldName: String
"""
Name of the field.
"""
name: String!
"""
Value of the field.
"""
value: Boolean!
}
"""
Represents the vulnerability details code field
"""
type VulnerabilityDetailCode {
"""
Description of the field.
"""
description: String!
"""
Name of the field.
"""
fieldName: String
"""
Language of the code.
"""
lang: String
"""
Name of the field.
"""
name: String!
"""
Source code.
"""
value: String!
}
"""
Represents the vulnerability details commit field
"""
type VulnerabilityDetailCommit {
"""
Description of the field.
"""
description: String!
"""
Name of the field.
"""
fieldName: String
"""
Name of the field.
"""
name: String!
"""
The commit SHA value.
"""
value: String!
}
"""
Represents the vulnerability details diff field
"""
type VulnerabilityDetailDiff {
"""
Value of the field after the change.
"""
after: String!
"""
Value of the field before the change.
"""
before: String!
"""
Description of the field.
"""
description: String!
"""
Name of the field.
"""
fieldName: String
"""
Name of the field.
"""
name: String!
}
"""
Represents the vulnerability details location within a file in the project
"""
type VulnerabilityDetailFileLocation {
"""
Description of the field.
"""
description: String!
"""
Name of the field.
"""
fieldName: String
"""
File name.
"""
fileName: String!
"""
End line number of the file location.
"""
lineEnd: Int!
"""
Start line number of the file location.
"""
lineStart: Int!
"""
Name of the field.
"""
name: String!
}
"""
Represents the vulnerability details integer value
"""
type VulnerabilityDetailInt {
"""
Description of the field.
"""
description: String!
"""
Name of the field.
"""
fieldName: String
"""
Name of the field.
"""
name: String!
"""
Value of the field.
"""
value: Int!
}
"""
Represents the vulnerability details list value
"""
type VulnerabilityDetailList {
"""
Description of the field.
"""
description: String!
"""
Name of the field.
"""
fieldName: String
"""
List of details.
"""
items: [VulnerabilityDetail!]!
"""
Name of the field.
"""
name: String!
}
"""
Represents the vulnerability details Markdown field
"""
type VulnerabilityDetailMarkdown {
"""
Description of the field.
"""
description: String!
"""
Name of the field.
"""
fieldName: String
"""
Name of the field.
"""
name: String!
"""
Value of the Markdown field.
"""
value: String!
}
"""
Represents the vulnerability details location within a file in the project
"""
type VulnerabilityDetailModuleLocation {
"""
Description of the field.
"""
description: String!
"""
Name of the field.
"""
fieldName: String
"""
Module name.
"""
moduleName: String!
"""
Name of the field.
"""
name: String!
"""
Offset of the module location.
"""
offset: Int!
}
"""
Represents the vulnerability details table value
"""
type VulnerabilityDetailTable {
"""
Description of the field.
"""
description: String!
"""
Name of the field.
"""
fieldName: String
"""
Table headers.
"""
headers: [VulnerabilityDetail!]!
"""
Name of the field.
"""
name: String!
"""
Table rows.
"""
rows: [VulnerabilityDetail!]!
}
"""
Represents the vulnerability details text field
"""
type VulnerabilityDetailText {
"""
Description of the field.
"""
description: String!
"""
Name of the field.
"""
fieldName: String
"""
Name of the field.
"""
name: String!
"""
Value of the text field.
"""
value: String!
}
"""
Represents the vulnerability details URL field
"""
type VulnerabilityDetailUrl {
"""
Description of the field.
"""
description: String!
"""
Name of the field.
"""
fieldName: String
"""
Href of the URL.
"""
href: String!
"""
Name of the field.
"""
name: String!
"""
Text of the URL.
"""
text: String
}
"""
Autogenerated input type of VulnerabilityDismiss
"""
......
......@@ -3847,6 +3847,7 @@ Represents a vulnerability.
| `confirmedAt` | Time | Timestamp of when the vulnerability state was changed to confirmed |
| `confirmedBy` | User | The user that confirmed the vulnerability. |
| `description` | String | Description of the vulnerability |
| `details` | VulnerabilityDetail! => Array | Details of the vulnerability |
| `detectedAt` | Time! | Timestamp of when the vulnerability was first detected |
| `discussions` | DiscussionConnection! | All discussions on this noteable |
| `dismissedAt` | Time | Timestamp of when the vulnerability state was changed to dismissed |
......@@ -3883,6 +3884,155 @@ Autogenerated return type of VulnerabilityConfirm.
| `errors` | String! => Array | Errors encountered during execution of the mutation. |
| `vulnerability` | Vulnerability | The vulnerability after state change |
### VulnerabilityDetailBase
Represents the vulnerability details base.
| Field | Type | Description |
| ----- | ---- | ----------- |
| `description` | String! | Description of the field. |
| `fieldName` | String | Name of the field. |
| `name` | String! | Name of the field. |
### VulnerabilityDetailBoolean
Represents the vulnerability details boolean value.
| Field | Type | Description |
| ----- | ---- | ----------- |
| `description` | String! | Description of the field. |
| `fieldName` | String | Name of the field. |
| `name` | String! | Name of the field. |
| `value` | Boolean! | Value of the field. |
### VulnerabilityDetailCode
Represents the vulnerability details code field.
| Field | Type | Description |
| ----- | ---- | ----------- |
| `description` | String! | Description of the field. |
| `fieldName` | String | Name of the field. |
| `lang` | String | Language of the code. |
| `name` | String! | Name of the field. |
| `value` | String! | Source code. |
### VulnerabilityDetailCommit
Represents the vulnerability details commit field.
| Field | Type | Description |
| ----- | ---- | ----------- |
| `description` | String! | Description of the field. |
| `fieldName` | String | Name of the field. |
| `name` | String! | Name of the field. |
| `value` | String! | The commit SHA value. |
### VulnerabilityDetailDiff
Represents the vulnerability details diff field.
| Field | Type | Description |
| ----- | ---- | ----------- |
| `after` | String! | Value of the field after the change. |
| `before` | String! | Value of the field before the change. |
| `description` | String! | Description of the field. |
| `fieldName` | String | Name of the field. |
| `name` | String! | Name of the field. |
### VulnerabilityDetailFileLocation
Represents the vulnerability details location within a file in the project.
| Field | Type | Description |
| ----- | ---- | ----------- |
| `description` | String! | Description of the field. |
| `fieldName` | String | Name of the field. |
| `fileName` | String! | File name. |
| `lineEnd` | Int! | End line number of the file location. |
| `lineStart` | Int! | Start line number of the file location. |
| `name` | String! | Name of the field. |
### VulnerabilityDetailInt
Represents the vulnerability details integer value.
| Field | Type | Description |
| ----- | ---- | ----------- |
| `description` | String! | Description of the field. |
| `fieldName` | String | Name of the field. |
| `name` | String! | Name of the field. |
| `value` | Int! | Value of the field. |
### VulnerabilityDetailList
Represents the vulnerability details list value.
| Field | Type | Description |
| ----- | ---- | ----------- |
| `description` | String! | Description of the field. |
| `fieldName` | String | Name of the field. |
| `items` | VulnerabilityDetail! => Array | List of details. |
| `name` | String! | Name of the field. |
### VulnerabilityDetailMarkdown
Represents the vulnerability details Markdown field.
| Field | Type | Description |
| ----- | ---- | ----------- |
| `description` | String! | Description of the field. |
| `fieldName` | String | Name of the field. |
| `name` | String! | Name of the field. |
| `value` | String! | Value of the Markdown field. |
### VulnerabilityDetailModuleLocation
Represents the vulnerability details location within a file in the project.
| Field | Type | Description |
| ----- | ---- | ----------- |
| `description` | String! | Description of the field. |
| `fieldName` | String | Name of the field. |
| `moduleName` | String! | Module name. |
| `name` | String! | Name of the field. |
| `offset` | Int! | Offset of the module location. |
### VulnerabilityDetailTable
Represents the vulnerability details table value.
| Field | Type | Description |
| ----- | ---- | ----------- |
| `description` | String! | Description of the field. |
| `fieldName` | String | Name of the field. |
| `headers` | VulnerabilityDetail! => Array | Table headers. |
| `name` | String! | Name of the field. |
| `rows` | VulnerabilityDetail! => Array | Table rows. |
### VulnerabilityDetailText
Represents the vulnerability details text field.
| Field | Type | Description |
| ----- | ---- | ----------- |
| `description` | String! | Description of the field. |
| `fieldName` | String | Name of the field. |
| `name` | String! | Name of the field. |
| `value` | String! | Value of the text field. |
### VulnerabilityDetailUrl
Represents the vulnerability details URL field.
| Field | Type | Description |
| ----- | ---- | ----------- |
| `description` | String! | Description of the field. |
| `fieldName` | String | Name of the field. |
| `href` | String! | Href of the URL. |
| `name` | String! | Name of the field. |
| `text` | String | Text of the URL. |
### VulnerabilityDismissPayload
Autogenerated return type of VulnerabilityDismiss.
......
# frozen_string_literal: true
module Resolvers
module Vulnerabilities
class DetailsResolver < BaseResolver
type [::Types::VulnerabilityDetailType], null: false
def resolve
return [] if object.finding_details.blank?
self.class.with_field_name(object.finding_details.with_indifferent_access)
end
def self.with_field_name(items)
return [] if items.blank?
items.map { |field_name, field| field.merge(field_name: field_name) }
end
end
end
end
# frozen_string_literal: true
module Types
class VulnerabilityDetailType < BaseUnion
UnexpectedReportType = Class.new(StandardError)
description 'Represents a vulnerability detail field. The fields with data will depend on the vulnerability detail type'
graphql_name 'VulnerabilityDetail'
possible_types VulnerabilityDetails::UrlType,
VulnerabilityDetails::IntType,
VulnerabilityDetails::ListType,
VulnerabilityDetails::CodeType,
VulnerabilityDetails::TextType,
VulnerabilityDetails::DiffType,
VulnerabilityDetails::TableType,
VulnerabilityDetails::BooleanType,
VulnerabilityDetails::CommitType,
VulnerabilityDetails::MarkdownType,
VulnerabilityDetails::FileLocationType,
VulnerabilityDetails::ModuleLocationType,
VulnerabilityDetails::BaseType
def self.resolve_type(object, context)
case object['type']
when 'url' then VulnerabilityDetails::UrlType
when 'code' then VulnerabilityDetails::CodeType
when 'text' then VulnerabilityDetails::TextType
when 'diff' then VulnerabilityDetails::DiffType
when 'table' then VulnerabilityDetails::TableType
when 'commit' then VulnerabilityDetails::CommitType
when 'markdown' then VulnerabilityDetails::MarkdownType
when 'file-location' then VulnerabilityDetails::FileLocationType
when 'module-location' then VulnerabilityDetails::ModuleLocationType
when 'list', 'named-list' then VulnerabilityDetails::ListType
else resolve_type_by_value(object['value'])
end
end
def self.resolve_type_by_value(value)
case value
when String then VulnerabilityDetails::TextType
when TrueClass, FalseClass then VulnerabilityDetails::BooleanType
when Integer then VulnerabilityDetails::IntType
else VulnerabilityDetails::BaseType
end
end
private_class_method :resolve_type_by_value
end
end
# frozen_string_literal: true
module Types
module VulnerabilityDetails
# rubocop: disable Graphql/AuthorizeTypes
class BaseType < BaseObject
graphql_name 'VulnerabilityDetailBase'
description 'Represents the vulnerability details base'
field :field_name, GraphQL::STRING_TYPE, null: true,
description: 'Name of the field.'
field :name, GraphQL::STRING_TYPE, null: false,
description: 'Name of the field.'
field :description, GraphQL::STRING_TYPE, null: false,
description: 'Description of the field.'
end
end
end
# frozen_string_literal: true
module Types
module VulnerabilityDetails
# rubocop: disable Graphql/AuthorizeTypes
class BooleanType < BaseType
graphql_name 'VulnerabilityDetailBoolean'
description 'Represents the vulnerability details boolean value'
field :value, GraphQL::BOOLEAN_TYPE, null: false,
description: 'Value of the field.'
end
end
end
# frozen_string_literal: true
module Types
module VulnerabilityDetails
# rubocop: disable Graphql/AuthorizeTypes
class CodeType < BaseType
graphql_name 'VulnerabilityDetailCode'
description 'Represents the vulnerability details code field'
field :lang, GraphQL::STRING_TYPE, null: true,
description: 'Language of the code.'
field :value, GraphQL::STRING_TYPE, null: false,
description: 'Source code.'
end
end
end
# frozen_string_literal: true
module Types
module VulnerabilityDetails
# rubocop: disable Graphql/AuthorizeTypes
class CommitType < BaseType
graphql_name 'VulnerabilityDetailCommit'
description 'Represents the vulnerability details commit field'
field :value, GraphQL::STRING_TYPE, null: false,
description: 'The commit SHA value.'
end
end
end
# frozen_string_literal: true
module Types
module VulnerabilityDetails
# rubocop: disable Graphql/AuthorizeTypes
class DiffType < BaseType
graphql_name 'VulnerabilityDetailDiff'
description 'Represents the vulnerability details diff field'
field :before, GraphQL::STRING_TYPE, null: false,
description: 'Value of the field before the change.'
field :after, GraphQL::STRING_TYPE, null: false,
description: 'Value of the field after the change.'
end
end
end
# frozen_string_literal: true
module Types
module VulnerabilityDetails
# rubocop: disable Graphql/AuthorizeTypes
class FileLocationType < BaseType
graphql_name 'VulnerabilityDetailFileLocation'
description 'Represents the vulnerability details location within a file in the project'
field :file_name, GraphQL::STRING_TYPE, null: false,
description: 'File name.'
field :line_start, GraphQL::INT_TYPE, null: false,
description: 'Start line number of the file location.'
field :line_end, GraphQL::INT_TYPE, null: false,
description: 'End line number of the file location.'
end
end
end
# frozen_string_literal: true
module Types
module VulnerabilityDetails
# rubocop: disable Graphql/AuthorizeTypes
class IntType < BaseType
graphql_name 'VulnerabilityDetailInt'
description 'Represents the vulnerability details integer value'
field :value, GraphQL::INT_TYPE, null: false,
description: 'Value of the field.'
end
end
end
# frozen_string_literal: true
module Types
module VulnerabilityDetails
# rubocop: disable Graphql/AuthorizeTypes
class ListType < BaseType
graphql_name 'VulnerabilityDetailList'
description 'Represents the vulnerability details list value'
field :items, [VulnerabilityDetailType], null: false,
description: 'List of details.'
def items
return object[:items] || [] if object[:type] == 'list'
::Resolvers::Vulnerabilities::DetailsResolver.with_field_name(object[:items])
end
end
end
end
# frozen_string_literal: true
module Types
module VulnerabilityDetails
# rubocop: disable Graphql/AuthorizeTypes
class MarkdownType < BaseType
graphql_name 'VulnerabilityDetailMarkdown'
description 'Represents the vulnerability details Markdown field'
field :value, GraphQL::STRING_TYPE, null: false,
description: 'Value of the Markdown field.'
end
end
end
# frozen_string_literal: true
module Types
module VulnerabilityDetails
# rubocop: disable Graphql/AuthorizeTypes
class ModuleLocationType < BaseType
graphql_name 'VulnerabilityDetailModuleLocation'
description 'Represents the vulnerability details location within a file in the project'
field :module_name, GraphQL::STRING_TYPE, null: false,
description: 'Module name.'
field :offset, GraphQL::INT_TYPE, null: false,
description: 'Offset of the module location.'
end
end
end
# frozen_string_literal: true
module Types
module VulnerabilityDetails
# rubocop: disable Graphql/AuthorizeTypes
class TableType < BaseType
graphql_name 'VulnerabilityDetailTable'
description 'Represents the vulnerability details table value'
field :headers, [VulnerabilityDetailType], null: false,
description: 'Table headers.'
field :rows, [VulnerabilityDetailType], null: false,
description: 'Table rows.'
def headers
::Resolvers::Vulnerabilities::DetailsResolver.with_field_name(object[:headers])
end
def rows
::Resolvers::Vulnerabilities::DetailsResolver.with_field_name(object[:rows])
end
end
end
end
# frozen_string_literal: true
module Types
module VulnerabilityDetails
# rubocop: disable Graphql/AuthorizeTypes
class TextType < BaseType
graphql_name 'VulnerabilityDetailText'
description 'Represents the vulnerability details text field'
field :value, GraphQL::STRING_TYPE, null: false,
description: 'Value of the text field.'
end
end
end
# frozen_string_literal: true
module Types
module VulnerabilityDetails
# rubocop: disable Graphql/AuthorizeTypes
class UrlType < BaseType
graphql_name 'VulnerabilityDetailUrl'
description 'Represents the vulnerability details URL field'
field :text, GraphQL::STRING_TYPE, null: true,
description: 'Text of the URL.'
field :href, GraphQL::STRING_TYPE, null: false,
description: 'Href of the URL.'
end
end
end
......@@ -90,6 +90,10 @@ module Types
field :dismissed_by, ::Types::UserType, null: true,
description: 'The user that dismissed the vulnerability.'
field :details, [VulnerabilityDetailType], null: false,
description: 'Details of the vulnerability',
resolver: Resolvers::Vulnerabilities::DetailsResolver
def confirmed_by
::Gitlab::Graphql::Loaders::BatchModelLoader.new(::User, object.confirmed_by_id).find
end
......
......@@ -117,7 +117,7 @@ module EE
scope :with_limit, -> (maximum) { limit(maximum) }
delegate :scanner_name, :scanner_external_id, :metadata, :message, :description,
delegate :scanner_name, :scanner_external_id, :metadata, :message, :description, :details,
to: :finding, prefix: true, allow_nil: true
delegate :default_branch, :name, to: :project, prefix: true, allow_nil: true
......
---
title: Add details to Vulnerability GraphQL
merge_request: 49465
author:
type: added
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Resolvers::Vulnerabilities::DetailsResolver do
include GraphqlHelpers
describe '.with_field_name' do
subject { described_class.with_field_name(items) }
context 'when there are no items' do
let(:items) { nil }
it { is_expected.to eq([]) }
end
context 'when there are items with field name' do
let(:items) do
{
field: {
value: :x
},
field_2: {
value: :y
}
}
end
it { is_expected.to eq([{ value: :x, field_name: :field }, { value: :y, field_name: :field_2 }]) }
end
end
describe '#resolve' do
subject { resolve(described_class, obj: vulnerability, args: {}, ctx: {}) }
let(:vulnerability) { double(finding_details: finding_details) }
context 'when there are no items in finding details' do
let(:finding_details) { nil }
it { is_expected.to eq([]) }
end
context 'when there are items in finding details' do
let(:finding_details) do
{
field: {
value: :x
},
field_2: {
value: :y
}
}
end
it { is_expected.to eq([{ 'field_name' => 'field', 'value' => :x }, { 'field_name' => 'field_2', 'value' => :y }]) }
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe GitlabSchema.types['VulnerabilityDetail'] do
let(:expected_types) do
[
Types::VulnerabilityDetails::UrlType,
Types::VulnerabilityDetails::IntType,
Types::VulnerabilityDetails::ListType,
Types::VulnerabilityDetails::CodeType,
Types::VulnerabilityDetails::TextType,
Types::VulnerabilityDetails::DiffType,
Types::VulnerabilityDetails::TableType,
Types::VulnerabilityDetails::CommitType,
Types::VulnerabilityDetails::BooleanType,
Types::VulnerabilityDetails::MarkdownType,
Types::VulnerabilityDetails::FileLocationType,
Types::VulnerabilityDetails::ModuleLocationType,
Types::VulnerabilityDetails::BaseType
]
end
it 'exposes all possible types' do
expect(described_class.possible_types).to contain_exactly(*expected_types)
end
describe '.resolve_type' do
using RSpec::Parameterized::TableSyntax
where(:type, :value, :graphql_type) do
'url' | nil | Types::VulnerabilityDetails::UrlType
'code' | nil | Types::VulnerabilityDetails::CodeType
'text' | nil | Types::VulnerabilityDetails::TextType
'diff' | nil | Types::VulnerabilityDetails::DiffType
'table' | nil | Types::VulnerabilityDetails::TableType
'commit' | nil | Types::VulnerabilityDetails::CommitType
'markdown' | nil | Types::VulnerabilityDetails::MarkdownType
'file-location' | nil | Types::VulnerabilityDetails::FileLocationType
'module-location' | nil | Types::VulnerabilityDetails::ModuleLocationType
'list' | nil | Types::VulnerabilityDetails::ListType
'named-list' | nil | Types::VulnerabilityDetails::ListType
'other' | nil | Types::VulnerabilityDetails::BaseType
'value' | nil | Types::VulnerabilityDetails::BaseType
'value' | '1' | Types::VulnerabilityDetails::TextType
'value' | 412 | Types::VulnerabilityDetails::IntType
'value' | true | Types::VulnerabilityDetails::BooleanType
'value' | false | Types::VulnerabilityDetails::BooleanType
end
with_them do
it 'correctly maps type in object to GraphQL type' do
expect(described_class.resolve_type({ 'type' => type, 'value' => value }, {})).to eq(graphql_type)
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe GitlabSchema.types['VulnerabilityDetailBase'] do
it { expect(described_class).to have_graphql_fields(:name, :description, :fieldName) }
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe GitlabSchema.types['VulnerabilityDetailBoolean'] do
it { expect(described_class).to have_graphql_fields(:name, :description, :fieldName, :value) }
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe GitlabSchema.types['VulnerabilityDetailCode'] do
it { expect(described_class).to have_graphql_fields(:name, :description, :fieldName, :lang, :value) }
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe GitlabSchema.types['VulnerabilityDetailCommit'] do
it { expect(described_class).to have_graphql_fields(:name, :description, :fieldName, :value) }
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe GitlabSchema.types['VulnerabilityDetailDiff'] do
it { expect(described_class).to have_graphql_fields(:name, :description, :fieldName, :before, :after) }
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe GitlabSchema.types['VulnerabilityDetailFileLocation'] do
it { expect(described_class).to have_graphql_fields(:name, :description, :fieldName, :fileName, :lineStart, :lineEnd) }
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe GitlabSchema.types['VulnerabilityDetailInt'] do
it { expect(described_class).to have_graphql_fields(:name, :description, :fieldName, :value) }
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe GitlabSchema.types['VulnerabilityDetailList'] do
it { expect(described_class).to have_graphql_fields(:name, :description, :fieldName, :items) }
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe GitlabSchema.types['VulnerabilityDetailMarkdown'] do
it { expect(described_class).to have_graphql_fields(:name, :description, :fieldName, :value) }
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe GitlabSchema.types['VulnerabilityDetailModuleLocation'] do
it { expect(described_class).to have_graphql_fields(:name, :description, :fieldName, :moduleName, :offset) }
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe GitlabSchema.types['VulnerabilityDetailTable'] do
it { expect(described_class).to have_graphql_fields(:name, :description, :fieldName, :headers, :rows) }
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe GitlabSchema.types['VulnerabilityDetailText'] do
it { expect(described_class).to have_graphql_fields(:name, :description, :fieldName, :value) }
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe GitlabSchema.types['VulnerabilityDetailUrl'] do
it { expect(described_class).to have_graphql_fields(:name, :description, :fieldName, :text, :href) }
end
......@@ -34,7 +34,8 @@ RSpec.describe GitlabSchema.types['Vulnerability'] do
discussions
confirmed_by
resolved_by
dismissed_by]
dismissed_by
details]
end
before do
......
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