diff --git a/app/assets/javascripts/graphql_shared/possible_types.json b/app/assets/javascripts/graphql_shared/possible_types.json index 7c7ca8d9097a6dff23efbc51aa001de8a1e571ed..3965d07dea7b09e1bd6e0feec0c352bee4b51148 100644 --- a/app/assets/javascripts/graphql_shared/possible_types.json +++ b/app/assets/javascripts/graphql_shared/possible_types.json @@ -298,6 +298,7 @@ "WorkItemWidgetTestReports", "WorkItemWidgetTimeTracking", "WorkItemWidgetVerificationStatus", + "WorkItemWidgetVulnerabilities", "WorkItemWidgetWeight" ], "WorkItemWidgetDefinition": [ diff --git a/app/models/work_items/widget_definition.rb b/app/models/work_items/widget_definition.rb index 3412197b78bd41fc1b411b066a2d623f11cbcd3c..21a4f0b0b517f9d1f9190c963f5cc17e64b358a3 100644 --- a/app/models/work_items/widget_definition.rb +++ b/app/models/work_items/widget_definition.rb @@ -45,7 +45,8 @@ class WidgetDefinition < ApplicationRecord custom_status: 26, linked_resources: 27, custom_fields: 28, # EE-only - error_tracking: 29 + error_tracking: 29, + vulnerabilities: 30 # EE-only } attribute :widget_options, ::Gitlab::Database::Type::IndifferentJsonb.new diff --git a/db/migrate/20250305122633_add_vulnerabilities_widget_to_work_item_types.rb b/db/migrate/20250305122633_add_vulnerabilities_widget_to_work_item_types.rb new file mode 100644 index 0000000000000000000000000000000000000000..1020a8acce0a6b855ed9e1c770a62fc25bcd396c --- /dev/null +++ b/db/migrate/20250305122633_add_vulnerabilities_widget_to_work_item_types.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +class AddVulnerabilitiesWidgetToWorkItemTypes < Gitlab::Database::Migration[2.2] + include Gitlab::Database::MigrationHelpers::WorkItems::Widgets + + restrict_gitlab_migration gitlab_schema: :gitlab_main + disable_ddl_transaction! + milestone '17.10' + + WORK_ITEM_TYPE_ENUM_VALUES = [0] # issue + + WIDGETS = [ + { + name: 'Vulnerabilities', + widget_type: 30 + } + ] + + def up + add_widget_definitions(type_enum_values: WORK_ITEM_TYPE_ENUM_VALUES, widgets: WIDGETS) + end + + def down + remove_widget_definitions(type_enum_values: WORK_ITEM_TYPE_ENUM_VALUES, widgets: WIDGETS) + end +end diff --git a/db/schema_migrations/20250305122633 b/db/schema_migrations/20250305122633 new file mode 100644 index 0000000000000000000000000000000000000000..2ccef334800afc7e3eb42d53c6d8266fa82de2b8 --- /dev/null +++ b/db/schema_migrations/20250305122633 @@ -0,0 +1 @@ +99672a385440dbf7119382fc9b722e6fb400ab743a1c5daeaa42e4af93837691 \ No newline at end of file diff --git a/doc/api/graphql/reference/_index.md b/doc/api/graphql/reference/_index.md index bd41f9f4fc1dd16921544f5ab2edb8755352d566..70fac136b35425f14099aea9fbd45c31eea34492 100644 --- a/doc/api/graphql/reference/_index.md +++ b/doc/api/graphql/reference/_index.md @@ -40374,6 +40374,17 @@ Represents a verification status widget. | <a id="workitemwidgetverificationstatustype"></a>`type` | [`WorkItemWidgetType`](#workitemwidgettype) | Widget type. | | <a id="workitemwidgetverificationstatusverificationstatus"></a>`verificationStatus` {{< icon name="warning-solid" >}} | [`String`](#string) | **Introduced** in GitLab 15.5. **Status**: Experiment. Verification status of the work item. | +### `WorkItemWidgetVulnerabilities` + +Represents a vulnerabilities widget. + +#### Fields + +| Name | Type | Description | +| ---- | ---- | ----------- | +| <a id="workitemwidgetvulnerabilitiesrelatedvulnerabilities"></a>`relatedVulnerabilities` {{< icon name="warning-solid" >}} | [`VulnerabilityConnection`](#vulnerabilityconnection) | **Introduced** in GitLab 17.10. **Status**: Experiment. Related vulnerabilities of the work item. | +| <a id="workitemwidgetvulnerabilitiestype"></a>`type` | [`WorkItemWidgetType`](#workitemwidgettype) | Widget type. | + ### `WorkItemWidgetWeight` Represents a weight widget. @@ -44283,6 +44294,7 @@ Type of a work item widget. | <a id="workitemwidgettypetest_reports"></a>`TEST_REPORTS` | Test Reports widget. | | <a id="workitemwidgettypetime_tracking"></a>`TIME_TRACKING` | Time Tracking widget. | | <a id="workitemwidgettypeverification_status"></a>`VERIFICATION_STATUS` | Verification Status widget. | +| <a id="workitemwidgettypevulnerabilities"></a>`VULNERABILITIES` | Vulnerabilities widget. | | <a id="workitemwidgettypeweight"></a>`WEIGHT` | Weight widget. | ### `WorkspaceVariableInputType` @@ -46690,6 +46702,7 @@ Implementations: - [`WorkItemWidgetTestReports`](#workitemwidgettestreports) - [`WorkItemWidgetTimeTracking`](#workitemwidgettimetracking) - [`WorkItemWidgetVerificationStatus`](#workitemwidgetverificationstatus) +- [`WorkItemWidgetVulnerabilities`](#workitemwidgetvulnerabilities) - [`WorkItemWidgetWeight`](#workitemwidgetweight) ##### Fields diff --git a/ee/app/graphql/ee/types/work_items/widget_interface.rb b/ee/app/graphql/ee/types/work_items/widget_interface.rb index f419af95aba8711610d39ee788e3c81f866a946f..046194ba72f10cd2e1722070428aab432d7caaf0 100644 --- a/ee/app/graphql/ee/types/work_items/widget_interface.rb +++ b/ee/app/graphql/ee/types/work_items/widget_interface.rb @@ -25,7 +25,8 @@ def type_mappings ::WorkItems::Widgets::RequirementLegacy => ::Types::WorkItems::Widgets::RequirementLegacyType, ::WorkItems::Widgets::TestReports => ::Types::WorkItems::Widgets::TestReportsType, ::WorkItems::Widgets::Color => ::Types::WorkItems::Widgets::ColorType, - ::WorkItems::Widgets::CustomFields => ::Types::WorkItems::Widgets::CustomFieldsType + ::WorkItems::Widgets::CustomFields => ::Types::WorkItems::Widgets::CustomFieldsType, + ::WorkItems::Widgets::Vulnerabilities => ::Types::WorkItems::Widgets::VulnerabilitiesType }.freeze orphan_types(*type_mappings.values) diff --git a/ee/app/graphql/types/work_items/widgets/vulnerabilities_type.rb b/ee/app/graphql/types/work_items/widgets/vulnerabilities_type.rb new file mode 100644 index 0000000000000000000000000000000000000000..7a8ff1eadc77134a6d4c8ff3fa91db317f438281 --- /dev/null +++ b/ee/app/graphql/types/work_items/widgets/vulnerabilities_type.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +module Types + module WorkItems + module Widgets + # rubocop:disable Graphql/AuthorizeTypes -- Disabling widget level authorization + class VulnerabilitiesType < BaseObject + graphql_name 'WorkItemWidgetVulnerabilities' + description 'Represents a vulnerabilities widget' + + implements ::Types::WorkItems::WidgetInterface + + field :related_vulnerabilities, ::Types::VulnerabilityType.connection_type, + null: true, + description: 'Related vulnerabilities of the work item.', + experiment: { milestone: '17.10' } + end + # rubocop:enable Graphql/AuthorizeTypes + end + end +end diff --git a/ee/app/models/ee/work_items/type.rb b/ee/app/models/ee/work_items/type.rb index 8f26a45d53b107a6df7f0064e8ecc81e3bc80c22..014c0ebd6afced69cdc06322f2ee6e106d5a2af4 100644 --- a/ee/app/models/ee/work_items/type.rb +++ b/ee/app/models/ee/work_items/type.rb @@ -18,7 +18,8 @@ module Type issuable_health_status: ::WorkItems::Widgets::HealthStatus, okrs: ::WorkItems::Widgets::Progress, epic_colors: ::WorkItems::Widgets::Color, - custom_fields: ::WorkItems::Widgets::CustomFields + custom_fields: ::WorkItems::Widgets::CustomFields, + security_dashboard: ::WorkItems::Widgets::Vulnerabilities }.freeze LICENSED_TYPES = { epic: :epics, objective: :okrs, key_result: :okrs, requirement: :requirements }.freeze diff --git a/ee/app/models/work_items/widgets/vulnerabilities.rb b/ee/app/models/work_items/widgets/vulnerabilities.rb new file mode 100644 index 0000000000000000000000000000000000000000..6f46c5b17befe4069f4f13dfc48abe5cc5f948e7 --- /dev/null +++ b/ee/app/models/work_items/widgets/vulnerabilities.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +module WorkItems + module Widgets + class Vulnerabilities < Base + delegate :related_vulnerabilities, to: :work_item + end + end +end diff --git a/ee/app/services/work_items/data_sync/widgets/vulnerabilities.rb b/ee/app/services/work_items/data_sync/widgets/vulnerabilities.rb new file mode 100644 index 0000000000000000000000000000000000000000..a13af441308b8d77603b1a0c060a5915a9911120 --- /dev/null +++ b/ee/app/services/work_items/data_sync/widgets/vulnerabilities.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module WorkItems + module DataSync + module Widgets + class Vulnerabilities < Base + def after_save_commit + # copy Vulnerabilities + end + + def post_move_cleanup + # do it + end + end + end + end +end diff --git a/ee/spec/graphql/types/work_items/widget_interface_spec.rb b/ee/spec/graphql/types/work_items/widget_interface_spec.rb index 523273da16bfef14569ad7c526ea73da35280ec5..4089a125cf99795a9e776758a9aacbfa63e07fb2 100644 --- a/ee/spec/graphql/types/work_items/widget_interface_spec.rb +++ b/ee/spec/graphql/types/work_items/widget_interface_spec.rb @@ -14,6 +14,7 @@ WorkItems::Widgets::Color | Types::WorkItems::Widgets::ColorType WorkItems::Widgets::RequirementLegacy | Types::WorkItems::Widgets::RequirementLegacyType WorkItems::Widgets::TestReports | Types::WorkItems::Widgets::TestReportsType + WorkItems::Widgets::Vulnerabilities | Types::WorkItems::Widgets::VulnerabilitiesType end with_them do diff --git a/ee/spec/graphql/types/work_items/widgets/vulnerabilities_type_spec.rb b/ee/spec/graphql/types/work_items/widgets/vulnerabilities_type_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..9969b3c34326b23ad8bfe0fba0d21d25b98652a9 --- /dev/null +++ b/ee/spec/graphql/types/work_items/widgets/vulnerabilities_type_spec.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Types::WorkItems::Widgets::VulnerabilitiesType, feature_category: :vulnerability_management do + let(:fields) do + %i[type related_vulnerabilities] + end + + specify { expect(described_class.graphql_name).to eq('WorkItemWidgetVulnerabilities') } + + specify { expect(described_class).to have_graphql_fields(fields) } +end diff --git a/ee/spec/models/ee/work_items/widget_definition_spec.rb b/ee/spec/models/ee/work_items/widget_definition_spec.rb index 98427d2e6fabad4784ac51c8b4cc1a46a1f1d5bb..0dd016d234a1c07cde5a5c1bd196331373523689 100644 --- a/ee/spec/models/ee/work_items/widget_definition_spec.rb +++ b/ee/spec/models/ee/work_items/widget_definition_spec.rb @@ -35,7 +35,8 @@ ::WorkItems::Widgets::EmailParticipants, ::WorkItems::Widgets::CustomStatus, ::WorkItems::Widgets::CustomFields, - ::WorkItems::Widgets::ErrorTracking + ::WorkItems::Widgets::ErrorTracking, + ::WorkItems::Widgets::Vulnerabilities ) end diff --git a/ee/spec/models/work_items/widgets/vulnerabilities_spec.rb b/ee/spec/models/work_items/widgets/vulnerabilities_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..cb9b2f9f795540d66c2b6eed428412537a288bb4 --- /dev/null +++ b/ee/spec/models/work_items/widgets/vulnerabilities_spec.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe WorkItems::Widgets::Vulnerabilities, feature_category: :vulnerability_management do + let_it_be(:work_item) { create(:work_item, :issue) } + + describe '#related_vulnerabilities' do + subject { described_class.new(work_item).related_vulnerabilities } + + it { is_expected.to eq(work_item.related_vulnerabilities) } + end +end diff --git a/lib/gitlab/database_importers/work_items/base_type_importer.rb b/lib/gitlab/database_importers/work_items/base_type_importer.rb index 35ed592fbd5e38aa2367ffa0961f740c9e73a615..3c553445c378bc30cc0f0bad244796d6072e4c1a 100644 --- a/lib/gitlab/database_importers/work_items/base_type_importer.rb +++ b/lib/gitlab/database_importers/work_items/base_type_importer.rb @@ -32,7 +32,8 @@ module BaseTypeImporter email_participants: 'Email participants', custom_status: 'Custom status', custom_fields: 'Custom fields', - error_tracking: 'Error tracking' + error_tracking: 'Error tracking', + vulnerabilities: 'Vulnerabilities' }.freeze WIDGETS_FOR_TYPE = { @@ -58,6 +59,7 @@ module BaseTypeImporter :participants, :start_and_due_date, :time_tracking, + :vulnerabilities, [:weight, { editable: true, rollup: false }] ], incident: [ diff --git a/spec/migrations/20250305122633_add_vulnerabilities_widget_to_work_item_types_spec.rb b/spec/migrations/20250305122633_add_vulnerabilities_widget_to_work_item_types_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..90625a378728e97b0168add236011eda4c7cc437 --- /dev/null +++ b/spec/migrations/20250305122633_add_vulnerabilities_widget_to_work_item_types_spec.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe AddVulnerabilitiesWidgetToWorkItemTypes, :migration, feature_category: :vulnerability_management do + it_behaves_like 'migration that adds widgets to a work item type' +end diff --git a/spec/models/work_items/widget_definition_spec.rb b/spec/models/work_items/widget_definition_spec.rb index bb922a11d19e1ffe8f4f475a4db6ac57cde8ccb5..d7dbf51eacf035ec064bd7b99c7a004da1ae41f4 100644 --- a/spec/models/work_items/widget_definition_spec.rb +++ b/spec/models/work_items/widget_definition_spec.rb @@ -36,7 +36,8 @@ ::WorkItems::Widgets::RequirementLegacy, ::WorkItems::Widgets::TestReports, ::WorkItems::Widgets::Color, - ::WorkItems::Widgets::CustomFields + ::WorkItems::Widgets::CustomFields, + ::WorkItems::Widgets::Vulnerabilities ] end