From 61bfbbe899d585de14a611ee4ff9ba8f7aa1a670 Mon Sep 17 00:00:00 2001 From: Hitesh Raghuvanshi Date: Fri, 26 Sep 2025 14:34:59 +0530 Subject: [PATCH 01/14] Added table and model for storing vulnerability resolution data --- db/docs/vulnerability_resolutions.yml | 13 ++++++++++ ...104000_create_vulnerability_resolutions.rb | 18 +++++++++++++ db/schema_migrations/20250925104000 | 1 + db/structure.sql | 26 +++++++++++++++++++ ee/app/models/ai/duo_workflows/workflow.rb | 1 + ee/app/models/vulnerabilities/finding.rb | 2 ++ ee/app/models/vulnerabilities/resolution.rb | 23 ++++++++++++++++ ee/app/models/vulnerability_resolution.rb | 16 ++++++++++++ 8 files changed, 100 insertions(+) create mode 100644 db/docs/vulnerability_resolutions.yml create mode 100644 db/migrate/20250925104000_create_vulnerability_resolutions.rb create mode 100644 db/schema_migrations/20250925104000 create mode 100644 ee/app/models/vulnerabilities/resolution.rb create mode 100644 ee/app/models/vulnerability_resolution.rb diff --git a/db/docs/vulnerability_resolutions.yml b/db/docs/vulnerability_resolutions.yml new file mode 100644 index 00000000000000..e7023ca5ed298f --- /dev/null +++ b/db/docs/vulnerability_resolutions.yml @@ -0,0 +1,13 @@ +--- +table_name: vulnerability_resolutions +classes: +- Vulnerabilities::Resolution +feature_categories: +- vulnerability_management +description: Stores the metadata for vulnerability resolution by duo workflow +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/191311 +milestone: '18.5' +gitlab_schema: gitlab_sec +sharding_key: + namespace_id: projects +table_size: small diff --git a/db/migrate/20250925104000_create_vulnerability_resolutions.rb b/db/migrate/20250925104000_create_vulnerability_resolutions.rb new file mode 100644 index 00000000000000..961230ea34c319 --- /dev/null +++ b/db/migrate/20250925104000_create_vulnerability_resolutions.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +class CreateVulnerabilityResolutions < Gitlab::Database::Migration[2.3] + milestone '18.5' + + def change + create_table :vulnerability_resolutions do |t| + t.timestamps_with_timezone null: false + + t.bigint :vulnerability_finding_id, null: false + t.bigint :workflow_id, null: false + t.bigint :merge_request_id, null: true + t.bigint :project_id, null: false + t.integer :status, limit: 2, null: false, default: 0 + t.float :readiness_score, null: false, default: 0.0 + end + end +end diff --git a/db/schema_migrations/20250925104000 b/db/schema_migrations/20250925104000 new file mode 100644 index 00000000000000..64d33ed5f13467 --- /dev/null +++ b/db/schema_migrations/20250925104000 @@ -0,0 +1 @@ +c0bebc5a2869f5f684e66bb43a67986f72e5874d64deba53af4ef2ecced4ac94 \ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index 03667dd3bf924b..614df07e1b9d86 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -28512,6 +28512,27 @@ CREATE TABLE vulnerability_representation_information ( vulnerability_occurrence_id bigint ); +CREATE TABLE vulnerability_resolutions ( + id bigint NOT NULL, + created_at timestamp with time zone NOT NULL, + updated_at timestamp with time zone NOT NULL, + vulnerability_finding_id bigint NOT NULL, + workflow_id bigint NOT NULL, + merge_request_id bigint, + project_id bigint NOT NULL, + status smallint DEFAULT 0 NOT NULL, + readiness_score double precision DEFAULT 0.0 NOT NULL +); + +CREATE SEQUENCE vulnerability_resolutions_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + +ALTER SEQUENCE vulnerability_resolutions_id_seq OWNED BY vulnerability_resolutions.id; + CREATE TABLE vulnerability_scanners ( id bigint NOT NULL, created_at timestamp with time zone NOT NULL, @@ -31609,6 +31630,8 @@ ALTER TABLE ONLY vulnerability_reads ALTER COLUMN id SET DEFAULT nextval('vulner ALTER TABLE ONLY vulnerability_remediations ALTER COLUMN id SET DEFAULT nextval('vulnerability_remediations_id_seq'::regclass); +ALTER TABLE ONLY vulnerability_resolutions ALTER COLUMN id SET DEFAULT nextval('vulnerability_resolutions_id_seq'::regclass); + ALTER TABLE ONLY vulnerability_scanners ALTER COLUMN id SET DEFAULT nextval('vulnerability_scanners_id_seq'::regclass); ALTER TABLE ONLY vulnerability_severity_overrides ALTER COLUMN id SET DEFAULT nextval('vulnerability_severity_overrides_id_seq'::regclass); @@ -35316,6 +35339,9 @@ ALTER TABLE ONLY vulnerability_remediations ALTER TABLE ONLY vulnerability_representation_information ADD CONSTRAINT vulnerability_representation_information_pkey PRIMARY KEY (vulnerability_id); +ALTER TABLE ONLY vulnerability_resolutions + ADD CONSTRAINT vulnerability_resolutions_pkey PRIMARY KEY (id); + ALTER TABLE ONLY vulnerability_scanners ADD CONSTRAINT vulnerability_scanners_pkey PRIMARY KEY (id); diff --git a/ee/app/models/ai/duo_workflows/workflow.rb b/ee/app/models/ai/duo_workflows/workflow.rb index 7d39818b7d2cd2..cd76c015aeeab1 100644 --- a/ee/app/models/ai/duo_workflows/workflow.rb +++ b/ee/app/models/ai/duo_workflows/workflow.rb @@ -18,6 +18,7 @@ class Workflow < ::ApplicationRecord has_many :events, class_name: 'Ai::DuoWorkflows::Event' has_many :workflows_workloads, class_name: 'Ai::DuoWorkflows::WorkflowsWorkload' has_many :workloads, through: :workflows_workloads, disable_joins: true + has_one :vulnerability_resolution, class_name: '::VulnerabilityResolution', inverse_of: :workflow validates :status, presence: true validates :goal, length: { maximum: 16_384 } diff --git a/ee/app/models/vulnerabilities/finding.rb b/ee/app/models/vulnerabilities/finding.rb index 4279427e8defeb..fb7fce0ca3c951 100644 --- a/ee/app/models/vulnerabilities/finding.rb +++ b/ee/app/models/vulnerabilities/finding.rb @@ -109,6 +109,8 @@ class Finding < ::SecApplicationRecord has_one :finding_evidence, class_name: 'Vulnerabilities::Finding::Evidence', inverse_of: :finding, foreign_key: 'vulnerability_occurrence_id' + has_many :vulnerability_resolutions, class_name: '::VulnerabilityResolution', inverse_of: :vulnerability_finding + has_many :security_findings, class_name: 'Security::Finding', primary_key: :uuid, diff --git a/ee/app/models/vulnerabilities/resolution.rb b/ee/app/models/vulnerabilities/resolution.rb new file mode 100644 index 00000000000000..5a7681e39c6c98 --- /dev/null +++ b/ee/app/models/vulnerabilities/resolution.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +module Vulnerabilities + class Resolution < ::SecApplicationRecord + self.table_name = 'vulnerability_resolutions' + + belongs_to :finding, class_name: '::Vulnerabilities::Finding', foreign_key: 'vulnerability_finding_id', inverse_of: :vulnerability_resolutions, optional: false + belongs_to :workflow, class_name: '::Ai::DuoWorkflows::Workflow', optional: true + belongs_to :merge_request, class_name: 'MergeRequest', optional: true + + validates :status, :project_id, presence: true + validates :workflow_id, uniqueness: true + validates :readiness_score, inclusion: { in: 0.0..1.0 } + + WORKFLOW_STATUSES = { + in_progress: 0, + completed: 1, + failed: 2 + }.freeze + + enum :status, WORKFLOW_STATUSES + end +end diff --git a/ee/app/models/vulnerability_resolution.rb b/ee/app/models/vulnerability_resolution.rb new file mode 100644 index 00000000000000..f3bea0487f9fb1 --- /dev/null +++ b/ee/app/models/vulnerability_resolution.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +class VulnerabilityResolution < ::ApplicationRecord + belongs_to :vulnerability_finding, class_name: 'Vulnerabilities::Finding' + belongs_to :workflow, class_name: 'Ai::DuoWorkflows::Workflow' + belongs_to :merge_request, optional: true + + validates :status, presence: true + validates :workflow_id, uniqueness: true + + enum :status, { + in_progress: 0, + completed: 1, + failed: 2 + } +end \ No newline at end of file -- GitLab From 77f022824189073d5c8f1887601175b2593f4dfe Mon Sep 17 00:00:00 2001 From: Hitesh Raghuvanshi Date: Mon, 29 Sep 2025 10:29:11 +0530 Subject: [PATCH 02/14] Added foreign keys --- db/docs/vulnerability_resolutions.yml | 3 ++- ...to_vulnerability_resolutions_finding_id.rb | 17 ++++++++++++ ...o_vulnerability_resolutions_workflow_id.rb | 26 +++++++++++++++++++ db/schema_migrations/20250926101216 | 1 + db/schema_migrations/20250926103019 | 1 + 5 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 db/migrate/20250926101216_add_foreign_key_to_vulnerability_resolutions_finding_id.rb create mode 100644 db/migrate/20250926103019_add_foreign_key_to_vulnerability_resolutions_workflow_id.rb create mode 100644 db/schema_migrations/20250926101216 create mode 100644 db/schema_migrations/20250926103019 diff --git a/db/docs/vulnerability_resolutions.yml b/db/docs/vulnerability_resolutions.yml index e7023ca5ed298f..6e19e5d889209c 100644 --- a/db/docs/vulnerability_resolutions.yml +++ b/db/docs/vulnerability_resolutions.yml @@ -2,10 +2,11 @@ table_name: vulnerability_resolutions classes: - Vulnerabilities::Resolution +- VulnerabilityResolution feature_categories: - vulnerability_management description: Stores the metadata for vulnerability resolution by duo workflow -introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/191311 +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/206498 milestone: '18.5' gitlab_schema: gitlab_sec sharding_key: diff --git a/db/migrate/20250926101216_add_foreign_key_to_vulnerability_resolutions_finding_id.rb b/db/migrate/20250926101216_add_foreign_key_to_vulnerability_resolutions_finding_id.rb new file mode 100644 index 00000000000000..b6a9fe5b486b1e --- /dev/null +++ b/db/migrate/20250926101216_add_foreign_key_to_vulnerability_resolutions_finding_id.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class AddForeignKeyToVulnerabilityResolutionsFindingId < Gitlab::Database::Migration[2.3] + milestone '18.5' + disable_ddl_transaction! + + def up + add_concurrent_foreign_key :vulnerability_resolutions, :vulnerability_occurrences, + column: :vulnerability_finding_id, on_delete: :cascade + end + + def down + with_lock_retries do + remove_foreign_key :vulnerability_resolutions, column: :vulnerability_finding_id + end + end +end diff --git a/db/migrate/20250926103019_add_foreign_key_to_vulnerability_resolutions_workflow_id.rb b/db/migrate/20250926103019_add_foreign_key_to_vulnerability_resolutions_workflow_id.rb new file mode 100644 index 00000000000000..7f267218b7ff8c --- /dev/null +++ b/db/migrate/20250926103019_add_foreign_key_to_vulnerability_resolutions_workflow_id.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +class AddForeignKeyToVulnerabilityResolutionsWorkflowId < Gitlab::Database::Migration[2.3] + milestone '18.5' + disable_ddl_transaction! + + UNIQ_INDEX_NAME = 'unique_vulnerability_resolutions_on_workflow_id' + + def up + add_concurrent_foreign_key :vulnerability_resolutions, :duo_workflows_workflows, column: :workflow_id + + unless index_exists?(:vulnerability_resolutions, :workflow_id, name: UNIQ_INDEX_NAME) + add_concurrent_index(:vulnerability_resolutions, :workflow_id, name: UNIQ_INDEX_NAME) + end + end + + def down + with_lock_retries do + remove_foreign_key :vulnerability_resolutions, column: :workflow_id + + if index_exists?(:vulnerability_resolutions, :workflow_id, name: UNIQ_INDEX_NAME) + remove_concurrent_index_by_name(:vulnerability_resolutions, UNIQ_INDEX_NAME) + end + end + end +end diff --git a/db/schema_migrations/20250926101216 b/db/schema_migrations/20250926101216 new file mode 100644 index 00000000000000..329402e2ad36e2 --- /dev/null +++ b/db/schema_migrations/20250926101216 @@ -0,0 +1 @@ +112726bc5e36fc73f68152d91de8bcd224b1356d661b6be7059aeaa3a8ae2cad \ No newline at end of file diff --git a/db/schema_migrations/20250926103019 b/db/schema_migrations/20250926103019 new file mode 100644 index 00000000000000..b07721b8494b48 --- /dev/null +++ b/db/schema_migrations/20250926103019 @@ -0,0 +1 @@ +ec8f5b70ce04261de8c823a33ca787a01e2af68f002def9c011b5f149e37f785 \ No newline at end of file -- GitLab From 1aa4e0a3887d364f0e4e201feac40624cdbd9bfb Mon Sep 17 00:00:00 2001 From: Hitesh Raghuvanshi Date: Mon, 29 Sep 2025 10:35:19 +0530 Subject: [PATCH 03/14] Added foreign keys --- db/structure.sql | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/db/structure.sql b/db/structure.sql index 614df07e1b9d86..9556e3daa4b6ae 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -43610,6 +43610,8 @@ CREATE UNIQUE INDEX unique_user_id_setting_type_and_settings_context_hash ON vs_ CREATE UNIQUE INDEX unique_vuln_merge_request_link_vuln_id_and_mr_id ON vulnerability_merge_request_links USING btree (vulnerability_id, merge_request_id); +CREATE INDEX unique_vulnerability_resolutions_on_workflow_id ON vulnerability_resolutions USING btree (workflow_id); + CREATE UNIQUE INDEX unique_zoekt_enabled_namespaces_on_root_namespace_id ON zoekt_enabled_namespaces USING btree (root_namespace_id); CREATE INDEX user_follow_users_followee_id_idx ON user_follow_users USING btree (followee_id); @@ -47806,6 +47808,9 @@ ALTER TABLE ONLY wiki_page_slugs ALTER TABLE ONLY security_orchestration_policy_rule_schedules ADD CONSTRAINT fk_3e78b9a150 FOREIGN KEY (namespace_id) REFERENCES namespaces(id) ON DELETE CASCADE; +ALTER TABLE ONLY vulnerability_resolutions + ADD CONSTRAINT fk_3f44621def FOREIGN KEY (vulnerability_finding_id) REFERENCES vulnerability_occurrences(id) ON DELETE CASCADE; + ALTER TABLE ONLY abuse_reports ADD CONSTRAINT fk_3fe6467b93 FOREIGN KEY (assignee_id) REFERENCES users(id) ON DELETE SET NULL; @@ -49372,6 +49377,9 @@ ALTER TABLE ONLY board_labels ALTER TABLE ONLY packages_debian_project_distribution_keys ADD CONSTRAINT fk_eb2224a3c0 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE; +ALTER TABLE ONLY vulnerability_resolutions + ADD CONSTRAINT fk_eba3f28622 FOREIGN KEY (workflow_id) REFERENCES duo_workflows_workflows(id) ON DELETE CASCADE; + ALTER TABLE ONLY compliance_requirements ADD CONSTRAINT fk_ebf5c3365b FOREIGN KEY (framework_id) REFERENCES compliance_management_frameworks(id) ON DELETE CASCADE; -- GitLab From 5a8689769b0f1dd28e6f5101fc4ea25bc9e641e2 Mon Sep 17 00:00:00 2001 From: Hitesh Raghuvanshi Date: Mon, 29 Sep 2025 10:41:14 +0530 Subject: [PATCH 04/14] Fixed association --- ee/app/models/ai/duo_workflows/workflow.rb | 2 +- ee/app/models/vulnerabilities/finding.rb | 2 +- ee/app/models/vulnerability_resolution.rb | 16 ---------------- 3 files changed, 2 insertions(+), 18 deletions(-) delete mode 100644 ee/app/models/vulnerability_resolution.rb diff --git a/ee/app/models/ai/duo_workflows/workflow.rb b/ee/app/models/ai/duo_workflows/workflow.rb index cd76c015aeeab1..debdaf1b6c193c 100644 --- a/ee/app/models/ai/duo_workflows/workflow.rb +++ b/ee/app/models/ai/duo_workflows/workflow.rb @@ -18,7 +18,7 @@ class Workflow < ::ApplicationRecord has_many :events, class_name: 'Ai::DuoWorkflows::Event' has_many :workflows_workloads, class_name: 'Ai::DuoWorkflows::WorkflowsWorkload' has_many :workloads, through: :workflows_workloads, disable_joins: true - has_one :vulnerability_resolution, class_name: '::VulnerabilityResolution', inverse_of: :workflow + has_many :vulnerability_resolutions, class_name: '::Vulnerabilities::Resolution', inverse_of: :workflow validates :status, presence: true validates :goal, length: { maximum: 16_384 } diff --git a/ee/app/models/vulnerabilities/finding.rb b/ee/app/models/vulnerabilities/finding.rb index fb7fce0ca3c951..7ee25abd4e71ab 100644 --- a/ee/app/models/vulnerabilities/finding.rb +++ b/ee/app/models/vulnerabilities/finding.rb @@ -109,7 +109,7 @@ class Finding < ::SecApplicationRecord has_one :finding_evidence, class_name: 'Vulnerabilities::Finding::Evidence', inverse_of: :finding, foreign_key: 'vulnerability_occurrence_id' - has_many :vulnerability_resolutions, class_name: '::VulnerabilityResolution', inverse_of: :vulnerability_finding + has_many :vulnerability_resolutions, class_name: '::Vulnerabilities::Resolution', inverse_of: :finding has_many :security_findings, class_name: 'Security::Finding', diff --git a/ee/app/models/vulnerability_resolution.rb b/ee/app/models/vulnerability_resolution.rb deleted file mode 100644 index f3bea0487f9fb1..00000000000000 --- a/ee/app/models/vulnerability_resolution.rb +++ /dev/null @@ -1,16 +0,0 @@ -# frozen_string_literal: true - -class VulnerabilityResolution < ::ApplicationRecord - belongs_to :vulnerability_finding, class_name: 'Vulnerabilities::Finding' - belongs_to :workflow, class_name: 'Ai::DuoWorkflows::Workflow' - belongs_to :merge_request, optional: true - - validates :status, presence: true - validates :workflow_id, uniqueness: true - - enum :status, { - in_progress: 0, - completed: 1, - failed: 2 - } -end \ No newline at end of file -- GitLab From 199cccc930c05aab41af8f69cc21cb1339bb0793 Mon Sep 17 00:00:00 2001 From: Hitesh Raghuvanshi Date: Mon, 29 Sep 2025 11:06:33 +0530 Subject: [PATCH 05/14] Removed status --- .../20250925104000_create_vulnerability_resolutions.rb | 1 - db/structure.sql | 1 - ee/app/models/vulnerabilities/resolution.rb | 9 --------- 3 files changed, 11 deletions(-) diff --git a/db/migrate/20250925104000_create_vulnerability_resolutions.rb b/db/migrate/20250925104000_create_vulnerability_resolutions.rb index 961230ea34c319..394711c8335a8d 100644 --- a/db/migrate/20250925104000_create_vulnerability_resolutions.rb +++ b/db/migrate/20250925104000_create_vulnerability_resolutions.rb @@ -11,7 +11,6 @@ def change t.bigint :workflow_id, null: false t.bigint :merge_request_id, null: true t.bigint :project_id, null: false - t.integer :status, limit: 2, null: false, default: 0 t.float :readiness_score, null: false, default: 0.0 end end diff --git a/db/structure.sql b/db/structure.sql index 9556e3daa4b6ae..d55294420d4447 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -28520,7 +28520,6 @@ CREATE TABLE vulnerability_resolutions ( workflow_id bigint NOT NULL, merge_request_id bigint, project_id bigint NOT NULL, - status smallint DEFAULT 0 NOT NULL, readiness_score double precision DEFAULT 0.0 NOT NULL ); diff --git a/ee/app/models/vulnerabilities/resolution.rb b/ee/app/models/vulnerabilities/resolution.rb index 5a7681e39c6c98..218f38175535a8 100644 --- a/ee/app/models/vulnerabilities/resolution.rb +++ b/ee/app/models/vulnerabilities/resolution.rb @@ -8,16 +8,7 @@ class Resolution < ::SecApplicationRecord belongs_to :workflow, class_name: '::Ai::DuoWorkflows::Workflow', optional: true belongs_to :merge_request, class_name: 'MergeRequest', optional: true - validates :status, :project_id, presence: true validates :workflow_id, uniqueness: true validates :readiness_score, inclusion: { in: 0.0..1.0 } - - WORKFLOW_STATUSES = { - in_progress: 0, - completed: 1, - failed: 2 - }.freeze - - enum :status, WORKFLOW_STATUSES end end -- GitLab From db6e021d3146a0f916425072b89869c574a5907a Mon Sep 17 00:00:00 2001 From: Hitesh Raghuvanshi Date: Mon, 29 Sep 2025 11:49:36 +0530 Subject: [PATCH 06/14] Removed unique index --- ...oreign_key_to_vulnerability_resolutions_workflow_id.rb | 8 -------- db/structure.sql | 2 -- ee/app/models/vulnerabilities/resolution.rb | 1 - 3 files changed, 11 deletions(-) diff --git a/db/migrate/20250926103019_add_foreign_key_to_vulnerability_resolutions_workflow_id.rb b/db/migrate/20250926103019_add_foreign_key_to_vulnerability_resolutions_workflow_id.rb index 7f267218b7ff8c..32f641cd891c77 100644 --- a/db/migrate/20250926103019_add_foreign_key_to_vulnerability_resolutions_workflow_id.rb +++ b/db/migrate/20250926103019_add_foreign_key_to_vulnerability_resolutions_workflow_id.rb @@ -8,19 +8,11 @@ class AddForeignKeyToVulnerabilityResolutionsWorkflowId < Gitlab::Database::Migr def up add_concurrent_foreign_key :vulnerability_resolutions, :duo_workflows_workflows, column: :workflow_id - - unless index_exists?(:vulnerability_resolutions, :workflow_id, name: UNIQ_INDEX_NAME) - add_concurrent_index(:vulnerability_resolutions, :workflow_id, name: UNIQ_INDEX_NAME) - end end def down with_lock_retries do remove_foreign_key :vulnerability_resolutions, column: :workflow_id - - if index_exists?(:vulnerability_resolutions, :workflow_id, name: UNIQ_INDEX_NAME) - remove_concurrent_index_by_name(:vulnerability_resolutions, UNIQ_INDEX_NAME) - end end end end diff --git a/db/structure.sql b/db/structure.sql index d55294420d4447..9a76956ac958e9 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -43609,8 +43609,6 @@ CREATE UNIQUE INDEX unique_user_id_setting_type_and_settings_context_hash ON vs_ CREATE UNIQUE INDEX unique_vuln_merge_request_link_vuln_id_and_mr_id ON vulnerability_merge_request_links USING btree (vulnerability_id, merge_request_id); -CREATE INDEX unique_vulnerability_resolutions_on_workflow_id ON vulnerability_resolutions USING btree (workflow_id); - CREATE UNIQUE INDEX unique_zoekt_enabled_namespaces_on_root_namespace_id ON zoekt_enabled_namespaces USING btree (root_namespace_id); CREATE INDEX user_follow_users_followee_id_idx ON user_follow_users USING btree (followee_id); diff --git a/ee/app/models/vulnerabilities/resolution.rb b/ee/app/models/vulnerabilities/resolution.rb index 218f38175535a8..9fb582d07646a0 100644 --- a/ee/app/models/vulnerabilities/resolution.rb +++ b/ee/app/models/vulnerabilities/resolution.rb @@ -8,7 +8,6 @@ class Resolution < ::SecApplicationRecord belongs_to :workflow, class_name: '::Ai::DuoWorkflows::Workflow', optional: true belongs_to :merge_request, class_name: 'MergeRequest', optional: true - validates :workflow_id, uniqueness: true validates :readiness_score, inclusion: { in: 0.0..1.0 } end end -- GitLab From ffea2155b4f7a2da0e9a2570a0f5c15fcd549302 Mon Sep 17 00:00:00 2001 From: Hitesh Raghuvanshi Date: Mon, 29 Sep 2025 15:17:34 +0530 Subject: [PATCH 07/14] Added indexes for foreign keys --- .../20250925104000_create_vulnerability_resolutions.rb | 4 ++++ db/structure.sql | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/db/migrate/20250925104000_create_vulnerability_resolutions.rb b/db/migrate/20250925104000_create_vulnerability_resolutions.rb index 394711c8335a8d..84ab46c7fbbc5c 100644 --- a/db/migrate/20250925104000_create_vulnerability_resolutions.rb +++ b/db/migrate/20250925104000_create_vulnerability_resolutions.rb @@ -12,6 +12,10 @@ def change t.bigint :merge_request_id, null: true t.bigint :project_id, null: false t.float :readiness_score, null: false, default: 0.0 + + t.index :vulnerability_finding_id + t.index :workflow_id, unique: true + t.index :merge_request_id end end end diff --git a/db/structure.sql b/db/structure.sql index 9a76956ac958e9..0caa6dbd96b766 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -42797,6 +42797,12 @@ CREATE UNIQUE INDEX index_vulnerability_reads_on_vulnerability_id ON vulnerabili CREATE UNIQUE INDEX index_vulnerability_remediations_on_project_id_and_checksum ON vulnerability_remediations USING btree (project_id, checksum); +CREATE INDEX index_vulnerability_resolutions_on_merge_request_id ON vulnerability_resolutions USING btree (merge_request_id); + +CREATE INDEX index_vulnerability_resolutions_on_vulnerability_finding_id ON vulnerability_resolutions USING btree (vulnerability_finding_id); + +CREATE UNIQUE INDEX index_vulnerability_resolutions_on_workflow_id ON vulnerability_resolutions USING btree (workflow_id); + CREATE UNIQUE INDEX index_vulnerability_risk_scores_on_vulnerability_finding ON vulnerability_finding_risk_scores USING btree (finding_id); CREATE INDEX index_vulnerability_risk_scores_on_vulnerability_project ON vulnerability_finding_risk_scores USING btree (project_id); -- GitLab From c79658d8b43f0e09ad10e7658dd725ea1f1551b8 Mon Sep 17 00:00:00 2001 From: Hitesh Raghuvanshi Date: Mon, 29 Sep 2025 18:21:49 +0530 Subject: [PATCH 08/14] Added test cases --- ee/app/models/vulnerabilities/resolution.rb | 3 +- .../resolution_documentation.md | 97 +++++++++++++++++++ .../factories/vulnerabilities/resolutions.rb | 14 +++ .../models/vulnerabilities/resolution_spec.rb | 79 +++++++++++++++ 4 files changed, 192 insertions(+), 1 deletion(-) create mode 100644 ee/app/models/vulnerabilities/resolution_documentation.md create mode 100644 ee/spec/factories/vulnerabilities/resolutions.rb create mode 100644 ee/spec/models/vulnerabilities/resolution_spec.rb diff --git a/ee/app/models/vulnerabilities/resolution.rb b/ee/app/models/vulnerabilities/resolution.rb index 9fb582d07646a0..dacde6f5fb82f4 100644 --- a/ee/app/models/vulnerabilities/resolution.rb +++ b/ee/app/models/vulnerabilities/resolution.rb @@ -5,9 +5,10 @@ class Resolution < ::SecApplicationRecord self.table_name = 'vulnerability_resolutions' belongs_to :finding, class_name: '::Vulnerabilities::Finding', foreign_key: 'vulnerability_finding_id', inverse_of: :vulnerability_resolutions, optional: false - belongs_to :workflow, class_name: '::Ai::DuoWorkflows::Workflow', optional: true + belongs_to :workflow, class_name: '::Ai::DuoWorkflows::Workflow', optional: false belongs_to :merge_request, class_name: 'MergeRequest', optional: true + validates :workflow_id, uniqueness: true validates :readiness_score, inclusion: { in: 0.0..1.0 } end end diff --git a/ee/app/models/vulnerabilities/resolution_documentation.md b/ee/app/models/vulnerabilities/resolution_documentation.md new file mode 100644 index 00000000000000..2fbb48db3cf278 --- /dev/null +++ b/ee/app/models/vulnerabilities/resolution_documentation.md @@ -0,0 +1,97 @@ +# Vulnerabilities::Resolution Model + +## Overview + +The `Vulnerabilities::Resolution` model represents AI-generated resolutions for security vulnerabilities found in GitLab projects. This model links vulnerability findings with AI Duo Workflows that can generate automated fixes and tracks the readiness score of these resolutions. + +## Database Schema + +- **Table**: `vulnerability_resolutions` +- **Primary Key**: `id` +- **Foreign Keys**: + - `vulnerability_finding_id` (required) - References `vulnerability_occurrences.id` + - `workflow_id` (optional, unique) - References `duo_workflows_workflows.id` + - `merge_request_id` (optional) - References `merge_requests.id` + - `project_id` (required) - References `projects.id` + +## Attributes + +- `readiness_score` (float, required, default: 0.0) - Score between 0.0 and 1.0 indicating how ready the resolution is +- `created_at` / `updated_at` - Standard Rails timestamps + +## Associations + +- `belongs_to :finding` - The vulnerability finding this resolution addresses +- `belongs_to :workflow` (optional) - The AI Duo Workflow that generated this resolution +- `belongs_to :merge_request` (optional) - The merge request containing the resolution + +## Validations + +- `workflow_id` must be unique (if present) +- `readiness_score` must be between 0.0 and 1.0 (inclusive) + +## Usage Examples + +```ruby +# Create a basic resolution +resolution = Vulnerabilities::Resolution.create!( + finding: vulnerability_finding, + readiness_score: 0.8 +) + +# Create a resolution with workflow +resolution = Vulnerabilities::Resolution.create!( + finding: vulnerability_finding, + workflow: duo_workflow, + readiness_score: 0.9 +) + +# Create a resolution with merge request +resolution = Vulnerabilities::Resolution.create!( + finding: vulnerability_finding, + workflow: duo_workflow, + merge_request: merge_request, + readiness_score: 1.0 +) + +# Query high-quality resolutions +high_quality = Vulnerabilities::Resolution.where('readiness_score >= ?', 0.8) + +# Query resolutions with workflows +with_workflows = Vulnerabilities::Resolution.where.not(workflow_id: nil) +``` + +## Factory Usage + +```ruby +# Basic resolution +create(:vulnerability_resolution) + +# With workflow +create(:vulnerability_resolution, :with_workflow) + +# With merge request +create(:vulnerability_resolution, :with_merge_request) + +# High readiness score +create(:vulnerability_resolution, :high_readiness) + +# Perfect readiness score +create(:vulnerability_resolution, :perfect_readiness) +``` + +## Test Coverage + +The model includes comprehensive test coverage for: +- Associations and validations +- Database constraints and referential integrity +- Edge cases and boundary conditions +- Query optimization and performance +- Factory functionality +- Model behavior and data integrity + +## Related Models + +- `Vulnerabilities::Finding` - The vulnerability finding being resolved +- `Ai::DuoWorkflows::Workflow` - The AI workflow generating the resolution +- `MergeRequest` - The merge request containing the fix \ No newline at end of file diff --git a/ee/spec/factories/vulnerabilities/resolutions.rb b/ee/spec/factories/vulnerabilities/resolutions.rb new file mode 100644 index 00000000000000..8a27c86d72f11e --- /dev/null +++ b/ee/spec/factories/vulnerabilities/resolutions.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :vulnerability_resolution, class: 'Vulnerabilities::Resolution' do + finding { association(:vulnerabilities_finding) } + workflow { association(:duo_workflows_workflow) } + merge_request { nil } + readiness_score { 0.5 } + + after(:build) do |resolution| + resolution.project_id = resolution.finding.project_id + end + end +end diff --git a/ee/spec/models/vulnerabilities/resolution_spec.rb b/ee/spec/models/vulnerabilities/resolution_spec.rb new file mode 100644 index 00000000000000..bdf66f435e768a --- /dev/null +++ b/ee/spec/models/vulnerabilities/resolution_spec.rb @@ -0,0 +1,79 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Vulnerabilities::Resolution, feature_category: :vulnerability_management do + describe 'associations' do + it 'validates association for finding id' do + is_expected.to belong_to(:finding).class_name('::Vulnerabilities::Finding') + .with_foreign_key('vulnerability_finding_id').inverse_of(:vulnerability_resolutions).required + end + + it { is_expected.to belong_to(:workflow).class_name('::Ai::DuoWorkflows::Workflow').required } + it { is_expected.to belong_to(:merge_request).class_name('MergeRequest').optional } + end + + describe 'validations' do + subject { create(:vulnerability_resolution) } + + it { is_expected.to validate_uniqueness_of(:workflow_id) } + it { is_expected.to validate_inclusion_of(:readiness_score).in_range(0.0..1.0) } + + describe 'readiness_score validation' do + it 'allows valid readiness scores' do + [0.0, 0.5, 1.0, 0.25, 0.75].each do |score| + resolution = build(:vulnerability_resolution, readiness_score: score) + expect(resolution).to be_valid + end + end + + it 'rejects invalid readiness scores' do + [-0.1, 1.1, -1.0, 2.0].each do |score| + resolution = build(:vulnerability_resolution, readiness_score: score) + expect(resolution).not_to be_valid + expect(resolution.errors[:readiness_score]).to include('is not included in the list') + end + end + end + + describe 'workflow_id uniqueness' do + let_it_be(:existing_resolution) { create(:vulnerability_resolution) } + + it 'prevents duplicate workflow_id' do + duplicate_resolution = build(:vulnerability_resolution, workflow_id: existing_resolution.workflow_id) + + expect(duplicate_resolution).not_to be_valid + expect(duplicate_resolution.errors[:workflow_id]).to include('has already been taken') + end + + it 'allows different workflow_ids' do + different_workflow = create(:duo_workflows_workflow) + new_resolution = build(:vulnerability_resolution, workflow: different_workflow) + + expect(new_resolution).to be_valid + end + end + end + + describe 'factory' do + it 'creates a valid vulnerability resolution' do + resolution = build(:vulnerability_resolution) + expect(resolution).to be_valid + end + + it 'creates a valid vulnerability resolution with all associations' do + resolution = create(:vulnerability_resolution) + + expect(resolution.finding).to be_present + expect(resolution.workflow).to be_present + expect(resolution.readiness_score).to be_between(0.0, 1.0) + end + + it 'creates a valid vulnerability resolution with merge request' do + merge_request = create(:merge_request) + resolution = create(:vulnerability_resolution, merge_request: merge_request) + + expect(resolution.merge_request).to eq(merge_request) + end + end +end -- GitLab From f3ed29ac785a45dc28b7f42285598fe50aec08b6 Mon Sep 17 00:00:00 2001 From: Hitesh Raghuvanshi Date: Mon, 29 Sep 2025 19:47:14 +0530 Subject: [PATCH 09/14] Added project id as foreign key --- db/docs/vulnerability_resolutions.yml | 2 +- ...925104000_create_vulnerability_resolutions.rb | 1 + ...ey_to_vulnerability_resolutions_project_id.rb | 16 ++++++++++++++++ db/schema_migrations/20250929135804 | 1 + db/structure.sql | 5 +++++ 5 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 db/migrate/20250929135804_add_foreign_key_to_vulnerability_resolutions_project_id.rb create mode 100644 db/schema_migrations/20250929135804 diff --git a/db/docs/vulnerability_resolutions.yml b/db/docs/vulnerability_resolutions.yml index 6e19e5d889209c..371fe5a3f0d584 100644 --- a/db/docs/vulnerability_resolutions.yml +++ b/db/docs/vulnerability_resolutions.yml @@ -10,5 +10,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/206498 milestone: '18.5' gitlab_schema: gitlab_sec sharding_key: - namespace_id: projects + project_id: projects table_size: small diff --git a/db/migrate/20250925104000_create_vulnerability_resolutions.rb b/db/migrate/20250925104000_create_vulnerability_resolutions.rb index 84ab46c7fbbc5c..6b1f31af750d2e 100644 --- a/db/migrate/20250925104000_create_vulnerability_resolutions.rb +++ b/db/migrate/20250925104000_create_vulnerability_resolutions.rb @@ -16,6 +16,7 @@ def change t.index :vulnerability_finding_id t.index :workflow_id, unique: true t.index :merge_request_id + t.index :project_id end end end diff --git a/db/migrate/20250929135804_add_foreign_key_to_vulnerability_resolutions_project_id.rb b/db/migrate/20250929135804_add_foreign_key_to_vulnerability_resolutions_project_id.rb new file mode 100644 index 00000000000000..9992cf74bc01b5 --- /dev/null +++ b/db/migrate/20250929135804_add_foreign_key_to_vulnerability_resolutions_project_id.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +class AddForeignKeyToVulnerabilityResolutionsProjectId < Gitlab::Database::Migration[2.3] + milestone '18.5' + disable_ddl_transaction! + + def up + add_concurrent_foreign_key :vulnerability_resolutions, :projects, column: :project_id + end + + def down + with_lock_retries do + remove_foreign_key :vulnerability_resolutions, column: :project_id + end + end +end diff --git a/db/schema_migrations/20250929135804 b/db/schema_migrations/20250929135804 new file mode 100644 index 00000000000000..4ff6b6b0d95114 --- /dev/null +++ b/db/schema_migrations/20250929135804 @@ -0,0 +1 @@ +bbccc0b80ab3320e4a9ea284b7670c49a39f7bc3fbfa660d4877fa4cd1fdb2b1 \ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index 0caa6dbd96b766..64660933d21fbd 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -42799,6 +42799,8 @@ CREATE UNIQUE INDEX index_vulnerability_remediations_on_project_id_and_checksum CREATE INDEX index_vulnerability_resolutions_on_merge_request_id ON vulnerability_resolutions USING btree (merge_request_id); +CREATE INDEX index_vulnerability_resolutions_on_project_id ON vulnerability_resolutions USING btree (project_id); + CREATE INDEX index_vulnerability_resolutions_on_vulnerability_finding_id ON vulnerability_resolutions USING btree (vulnerability_finding_id); CREATE UNIQUE INDEX index_vulnerability_resolutions_on_workflow_id ON vulnerability_resolutions USING btree (workflow_id); @@ -48384,6 +48386,9 @@ ALTER TABLE ONLY bulk_import_export_uploads ALTER TABLE ONLY merge_request_metrics ADD CONSTRAINT fk_7f28d925f3 FOREIGN KEY (merged_by_id) REFERENCES users(id) ON DELETE SET NULL; +ALTER TABLE ONLY vulnerability_resolutions + ADD CONSTRAINT fk_7f31d42e99 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE; + ALTER TABLE ONLY namespaces ADD CONSTRAINT fk_7f813d8c90 FOREIGN KEY (parent_id) REFERENCES namespaces(id) ON DELETE RESTRICT NOT VALID; -- GitLab From bd8c3abff5bd16c8890b4c856d9a783c6141ee9c Mon Sep 17 00:00:00 2001 From: Hitesh Raghuvanshi Date: Mon, 29 Sep 2025 20:10:00 +0530 Subject: [PATCH 10/14] Added merge request foreign key --- ...ulnerability_resolutions_merge_request_id.rb | 17 +++++++++++++++++ db/schema_migrations/20250929142629 | 1 + db/structure.sql | 3 +++ 3 files changed, 21 insertions(+) create mode 100644 db/migrate/20250929142629_add_foreign_key_to_vulnerability_resolutions_merge_request_id.rb create mode 100644 db/schema_migrations/20250929142629 diff --git a/db/migrate/20250929142629_add_foreign_key_to_vulnerability_resolutions_merge_request_id.rb b/db/migrate/20250929142629_add_foreign_key_to_vulnerability_resolutions_merge_request_id.rb new file mode 100644 index 00000000000000..4eb885b47a1964 --- /dev/null +++ b/db/migrate/20250929142629_add_foreign_key_to_vulnerability_resolutions_merge_request_id.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class AddForeignKeyToVulnerabilityResolutionsMergeRequestId < Gitlab::Database::Migration[2.3] + milestone '18.5' + disable_ddl_transaction! + + def up + add_concurrent_foreign_key :vulnerability_resolutions, :merge_requests, column: :merge_request_id, + on_delete: :nullify + end + + def down + with_lock_retries do + remove_foreign_key :vulnerability_resolutions, column: :merge_request_id + end + end +end diff --git a/db/schema_migrations/20250929142629 b/db/schema_migrations/20250929142629 new file mode 100644 index 00000000000000..0152c4ab2f4e22 --- /dev/null +++ b/db/schema_migrations/20250929142629 @@ -0,0 +1 @@ +4f4efef3064b00c542f09356309d6a9b06d3b6cbfd53d05fcd86767815819aa8 \ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index 64660933d21fbd..66432f61229dfb 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -47291,6 +47291,9 @@ ALTER TABLE ONLY lists ALTER TABLE ONLY subscription_user_add_on_assignments ADD CONSTRAINT fk_0d89020c49 FOREIGN KEY (add_on_purchase_id) REFERENCES subscription_add_on_purchases(id) ON DELETE CASCADE; +ALTER TABLE ONLY vulnerability_resolutions + ADD CONSTRAINT fk_0ddc4a650b FOREIGN KEY (merge_request_id) REFERENCES merge_requests(id) ON DELETE SET NULL; + ALTER TABLE ONLY approval_project_rules_users ADD CONSTRAINT fk_0dfcd9e339 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE; -- GitLab From 049a65754424abf8fc46001723a688491da5fb14 Mon Sep 17 00:00:00 2001 From: Hitesh Raghuvanshi Date: Mon, 29 Sep 2025 21:41:52 +0530 Subject: [PATCH 11/14] Fixed failins rspec --- db/docs/vulnerability_resolutions.yml | 1 - ee/spec/models/vulnerabilities/resolution_spec.rb | 2 +- spec/lib/gitlab/import_export/all_models.yml | 1 + 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/db/docs/vulnerability_resolutions.yml b/db/docs/vulnerability_resolutions.yml index 371fe5a3f0d584..b4cefa67ce234c 100644 --- a/db/docs/vulnerability_resolutions.yml +++ b/db/docs/vulnerability_resolutions.yml @@ -2,7 +2,6 @@ table_name: vulnerability_resolutions classes: - Vulnerabilities::Resolution -- VulnerabilityResolution feature_categories: - vulnerability_management description: Stores the metadata for vulnerability resolution by duo workflow diff --git a/ee/spec/models/vulnerabilities/resolution_spec.rb b/ee/spec/models/vulnerabilities/resolution_spec.rb index bdf66f435e768a..ce9d77fea345dc 100644 --- a/ee/spec/models/vulnerabilities/resolution_spec.rb +++ b/ee/spec/models/vulnerabilities/resolution_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Vulnerabilities::Resolution, feature_category: :vulnerability_management do +RSpec.describe Vulnerabilities::Rebundlsolution, feature_category: :vulnerability_management do describe 'associations' do it 'validates association for finding id' do is_expected.to belong_to(:finding).class_name('::Vulnerabilities::Finding') diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml index d98fb6bdc1693d..b966f2978be648 100644 --- a/spec/lib/gitlab/import_export/all_models.yml +++ b/spec/lib/gitlab/import_export/all_models.yml @@ -1288,6 +1288,7 @@ vulnerability_finding: - security_findings - finding_token_status - finding_risk_score + - vulnerability_resolutions scanner: - findings - security_findings -- GitLab From ca84e3767fa7f004c17719ae38105ebc4e7b11a8 Mon Sep 17 00:00:00 2001 From: Hitesh Raghuvanshi Date: Mon, 29 Sep 2025 21:47:20 +0530 Subject: [PATCH 12/14] Removed documentation --- .../resolution_documentation.md | 97 ------------------- 1 file changed, 97 deletions(-) delete mode 100644 ee/app/models/vulnerabilities/resolution_documentation.md diff --git a/ee/app/models/vulnerabilities/resolution_documentation.md b/ee/app/models/vulnerabilities/resolution_documentation.md deleted file mode 100644 index 2fbb48db3cf278..00000000000000 --- a/ee/app/models/vulnerabilities/resolution_documentation.md +++ /dev/null @@ -1,97 +0,0 @@ -# Vulnerabilities::Resolution Model - -## Overview - -The `Vulnerabilities::Resolution` model represents AI-generated resolutions for security vulnerabilities found in GitLab projects. This model links vulnerability findings with AI Duo Workflows that can generate automated fixes and tracks the readiness score of these resolutions. - -## Database Schema - -- **Table**: `vulnerability_resolutions` -- **Primary Key**: `id` -- **Foreign Keys**: - - `vulnerability_finding_id` (required) - References `vulnerability_occurrences.id` - - `workflow_id` (optional, unique) - References `duo_workflows_workflows.id` - - `merge_request_id` (optional) - References `merge_requests.id` - - `project_id` (required) - References `projects.id` - -## Attributes - -- `readiness_score` (float, required, default: 0.0) - Score between 0.0 and 1.0 indicating how ready the resolution is -- `created_at` / `updated_at` - Standard Rails timestamps - -## Associations - -- `belongs_to :finding` - The vulnerability finding this resolution addresses -- `belongs_to :workflow` (optional) - The AI Duo Workflow that generated this resolution -- `belongs_to :merge_request` (optional) - The merge request containing the resolution - -## Validations - -- `workflow_id` must be unique (if present) -- `readiness_score` must be between 0.0 and 1.0 (inclusive) - -## Usage Examples - -```ruby -# Create a basic resolution -resolution = Vulnerabilities::Resolution.create!( - finding: vulnerability_finding, - readiness_score: 0.8 -) - -# Create a resolution with workflow -resolution = Vulnerabilities::Resolution.create!( - finding: vulnerability_finding, - workflow: duo_workflow, - readiness_score: 0.9 -) - -# Create a resolution with merge request -resolution = Vulnerabilities::Resolution.create!( - finding: vulnerability_finding, - workflow: duo_workflow, - merge_request: merge_request, - readiness_score: 1.0 -) - -# Query high-quality resolutions -high_quality = Vulnerabilities::Resolution.where('readiness_score >= ?', 0.8) - -# Query resolutions with workflows -with_workflows = Vulnerabilities::Resolution.where.not(workflow_id: nil) -``` - -## Factory Usage - -```ruby -# Basic resolution -create(:vulnerability_resolution) - -# With workflow -create(:vulnerability_resolution, :with_workflow) - -# With merge request -create(:vulnerability_resolution, :with_merge_request) - -# High readiness score -create(:vulnerability_resolution, :high_readiness) - -# Perfect readiness score -create(:vulnerability_resolution, :perfect_readiness) -``` - -## Test Coverage - -The model includes comprehensive test coverage for: -- Associations and validations -- Database constraints and referential integrity -- Edge cases and boundary conditions -- Query optimization and performance -- Factory functionality -- Model behavior and data integrity - -## Related Models - -- `Vulnerabilities::Finding` - The vulnerability finding being resolved -- `Ai::DuoWorkflows::Workflow` - The AI workflow generating the resolution -- `MergeRequest` - The merge request containing the fix \ No newline at end of file -- GitLab From 25b65b68b001d0ad15d4f4baf037d19340fe4718 Mon Sep 17 00:00:00 2001 From: Hitesh Raghuvanshi Date: Mon, 29 Sep 2025 21:59:19 +0530 Subject: [PATCH 13/14] Fixed rubocop --- db/migrate/20250925104000_create_vulnerability_resolutions.rb | 2 +- ee/app/models/vulnerabilities/resolution.rb | 3 ++- ee/spec/models/vulnerabilities/resolution_spec.rb | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/db/migrate/20250925104000_create_vulnerability_resolutions.rb b/db/migrate/20250925104000_create_vulnerability_resolutions.rb index 6b1f31af750d2e..b44f6cda4b63f2 100644 --- a/db/migrate/20250925104000_create_vulnerability_resolutions.rb +++ b/db/migrate/20250925104000_create_vulnerability_resolutions.rb @@ -4,7 +4,7 @@ class CreateVulnerabilityResolutions < Gitlab::Database::Migration[2.3] milestone '18.5' def change - create_table :vulnerability_resolutions do |t| + create_table :vulnerability_resolutions do |t| # rubocop:disable Migration/EnsureFactoryForTable -- https://gitlab.com/gitlab-org/gitlab/-/issues/468630 t.timestamps_with_timezone null: false t.bigint :vulnerability_finding_id, null: false diff --git a/ee/app/models/vulnerabilities/resolution.rb b/ee/app/models/vulnerabilities/resolution.rb index dacde6f5fb82f4..cc170949abad96 100644 --- a/ee/app/models/vulnerabilities/resolution.rb +++ b/ee/app/models/vulnerabilities/resolution.rb @@ -4,7 +4,8 @@ module Vulnerabilities class Resolution < ::SecApplicationRecord self.table_name = 'vulnerability_resolutions' - belongs_to :finding, class_name: '::Vulnerabilities::Finding', foreign_key: 'vulnerability_finding_id', inverse_of: :vulnerability_resolutions, optional: false + belongs_to :finding, class_name: '::Vulnerabilities::Finding', foreign_key: 'vulnerability_finding_id', + inverse_of: :vulnerability_resolutions, optional: false belongs_to :workflow, class_name: '::Ai::DuoWorkflows::Workflow', optional: false belongs_to :merge_request, class_name: 'MergeRequest', optional: true diff --git a/ee/spec/models/vulnerabilities/resolution_spec.rb b/ee/spec/models/vulnerabilities/resolution_spec.rb index ce9d77fea345dc..bdf66f435e768a 100644 --- a/ee/spec/models/vulnerabilities/resolution_spec.rb +++ b/ee/spec/models/vulnerabilities/resolution_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Vulnerabilities::Rebundlsolution, feature_category: :vulnerability_management do +RSpec.describe Vulnerabilities::Resolution, feature_category: :vulnerability_management do describe 'associations' do it 'validates association for finding id' do is_expected.to belong_to(:finding).class_name('::Vulnerabilities::Finding') -- GitLab From 035a520a22fa57dfdfde8270e69bbdfa52d21b27 Mon Sep 17 00:00:00 2001 From: Hitesh Raghuvanshi Date: Tue, 30 Sep 2025 11:27:19 +0530 Subject: [PATCH 14/14] Fixed rspecs --- .../models/vulnerabilities/resolution_spec.rb | 29 ++++--------------- 1 file changed, 6 insertions(+), 23 deletions(-) diff --git a/ee/spec/models/vulnerabilities/resolution_spec.rb b/ee/spec/models/vulnerabilities/resolution_spec.rb index bdf66f435e768a..3d5023aaa020f4 100644 --- a/ee/spec/models/vulnerabilities/resolution_spec.rb +++ b/ee/spec/models/vulnerabilities/resolution_spec.rb @@ -14,7 +14,12 @@ end describe 'validations' do - subject { create(:vulnerability_resolution) } + let_it_be(:project) { create(:project, :with_vulnerability) } + + let_it_be(:finding) { create(:vulnerabilities_finding, vulnerability: project.vulnerabilities.first) } + let_it_be(:workflow) { create(:duo_workflows_workflow, project: project) } + + subject { create(:vulnerability_resolution, finding: finding, workflow: workflow, project_id: project.id) } it { is_expected.to validate_uniqueness_of(:workflow_id) } it { is_expected.to validate_inclusion_of(:readiness_score).in_range(0.0..1.0) } @@ -54,26 +59,4 @@ end end end - - describe 'factory' do - it 'creates a valid vulnerability resolution' do - resolution = build(:vulnerability_resolution) - expect(resolution).to be_valid - end - - it 'creates a valid vulnerability resolution with all associations' do - resolution = create(:vulnerability_resolution) - - expect(resolution.finding).to be_present - expect(resolution.workflow).to be_present - expect(resolution.readiness_score).to be_between(0.0, 1.0) - end - - it 'creates a valid vulnerability resolution with merge request' do - merge_request = create(:merge_request) - resolution = create(:vulnerability_resolution, merge_request: merge_request) - - expect(resolution.merge_request).to eq(merge_request) - end - end end -- GitLab