diff --git a/config/feature_flags/gitlab_com_derisk/policy_violations_es_filter.yml b/config/feature_flags/gitlab_com_derisk/policy_violations_es_filter.yml
new file mode 100644
index 0000000000000000000000000000000000000000..07d346568e3ce217c3f56f540b16bdbcf6ad7472
--- /dev/null
+++ b/config/feature_flags/gitlab_com_derisk/policy_violations_es_filter.yml
@@ -0,0 +1,10 @@
+---
+name: policy_violations_es_filter
+description:
+feature_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/561739
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/207947
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/577591
+milestone: '18.6'
+group: group::security policies
+type: gitlab_com_derisk
+default_enabled: false
diff --git a/doc/api/graphql/reference/_index.md b/doc/api/graphql/reference/_index.md
index 5577fa57ae3c2b211f27bc0074522c1846904b2b..03639d2fd31318582447d693988ffd58f664b32d 100644
--- a/doc/api/graphql/reference/_index.md
+++ b/doc/api/graphql/reference/_index.md
@@ -1993,6 +1993,7 @@ four standard [pagination arguments](#pagination-arguments):
| `image` | [`[String!]`](#string) | Filter vulnerabilities by location image. When this filter is present, the response only matches entries for a `reportType` that includes `container_scanning`, `cluster_image_scanning`. |
| `owaspTopTen` | [`[VulnerabilityOwaspTop10!]`](#vulnerabilityowasptop10) | Filter vulnerabilities by OWASP Top 10 2017 category. Wildcard value `NONE` is also supported but it cannot be combined with other OWASP top 10 values. |
| `owaspTopTen2021` {{< icon name="warning-solid" >}} | [`[VulnerabilityOwasp2021Top10!]`](#vulnerabilityowasp2021top10) | **Introduced** in GitLab 18.1. **Status**: Experiment. Filter vulnerabilities by OWASP Top 10 2021 category. Wildcard value `NONE` is also supported but it cannot be combined with other OWASP top 10 2021 values. To use this argument, you must have Elasticsearch configured and the `advanced_vulnerability_management` feature flag enabled. Not supported on Instance Security Dashboard queries. |
+| `policyViolations` {{< icon name="warning-solid" >}} | [`[PolicyViolations!]`](#policyviolations) | **Introduced** in GitLab 18.6. **Status**: Experiment. Filter by security policy violations. To use this argument, you must have Elasticsearch configured and the `advanced_vulnerability_management` feature flag enabled. Not supported on Instance Security Dashboard queries. |
| `projectId` | [`[ID!]`](#id) | Filter vulnerabilities by project. |
| `reachability` {{< icon name="warning-solid" >}} | [`ReachabilityType`](#reachabilitytype) | **Introduced** in GitLab 18.2. **Status**: Experiment. Filter vulnerabilities by reachability. |
| `reportType` | [`[VulnerabilityReportType!]`](#vulnerabilityreporttype) | Filter vulnerabilities by report type. |
@@ -32876,6 +32877,7 @@ four standard [pagination arguments](#pagination-arguments):
| `image` | [`[String!]`](#string) | Filter vulnerabilities by location image. When this filter is present, the response only matches entries for a `reportType` that includes `container_scanning`, `cluster_image_scanning`. |
| `owaspTopTen` | [`[VulnerabilityOwaspTop10!]`](#vulnerabilityowasptop10) | Filter vulnerabilities by OWASP Top 10 2017 category. Wildcard value `NONE` is also supported but it cannot be combined with other OWASP top 10 values. |
| `owaspTopTen2021` {{< icon name="warning-solid" >}} | [`[VulnerabilityOwasp2021Top10!]`](#vulnerabilityowasp2021top10) | **Introduced** in GitLab 18.1. **Status**: Experiment. Filter vulnerabilities by OWASP Top 10 2021 category. Wildcard value `NONE` is also supported but it cannot be combined with other OWASP top 10 2021 values. To use this argument, you must have Elasticsearch configured and the `advanced_vulnerability_management` feature flag enabled. Not supported on Instance Security Dashboard queries. |
+| `policyViolations` {{< icon name="warning-solid" >}} | [`[PolicyViolations!]`](#policyviolations) | **Introduced** in GitLab 18.6. **Status**: Experiment. Filter by security policy violations. To use this argument, you must have Elasticsearch configured and the `advanced_vulnerability_management` feature flag enabled. Not supported on Instance Security Dashboard queries. |
| `projectId` | [`[ID!]`](#id) | Filter vulnerabilities by project. |
| `reachability` {{< icon name="warning-solid" >}} | [`ReachabilityType`](#reachabilitytype) | **Introduced** in GitLab 18.2. **Status**: Experiment. Filter vulnerabilities by reachability. |
| `reportType` | [`[VulnerabilityReportType!]`](#vulnerabilityreporttype) | Filter vulnerabilities by report type. |
@@ -32973,6 +32975,7 @@ Returns [`VulnerabilitySeveritiesCount`](#vulnerabilityseveritiescount).
| `image` | [`[String!]`](#string) | Filter vulnerabilities by location image. When this filter is present, the response only matches entries for a `reportType` that includes `container_scanning`, `cluster_image_scanning`. |
| `owaspTopTen` | [`[VulnerabilityOwaspTop10!]`](#vulnerabilityowasptop10) | Filter vulnerabilities by OWASP Top 10 2017 category. Wildcard value `NONE` is also supported but it cannot be combined with other OWASP top 10 values. |
| `owaspTopTen2021` {{< icon name="warning-solid" >}} | [`[VulnerabilityOwasp2021Top10!]`](#vulnerabilityowasp2021top10) | **Introduced** in GitLab 18.1. **Status**: Experiment. Filter vulnerabilities by OWASP Top 10 2021 category. Wildcard value `NONE` is also supported but it cannot be combined with other OWASP top 10 2021 values. To use this argument, you must have Elasticsearch configured and the `advanced_vulnerability_management` feature flag enabled. Not supported on Instance Security Dashboard queries. |
+| `policyViolations` {{< icon name="warning-solid" >}} | [`[PolicyViolations!]`](#policyviolations) | **Introduced** in GitLab 18.6. **Status**: Experiment. Filter by security policy violations. To use this argument, you must have Elasticsearch configured and the `advanced_vulnerability_management` feature flag enabled. Not supported on Instance Security Dashboard queries. |
| `projectId` | [`[ID!]`](#id) | Filter vulnerabilities by project. |
| `reachability` {{< icon name="warning-solid" >}} | [`ReachabilityType`](#reachabilitytype) | **Introduced** in GitLab 18.2. **Status**: Experiment. Filter vulnerabilities by reachability. |
| `reportType` | [`[VulnerabilityReportType!]`](#vulnerabilityreporttype) | Filter vulnerabilities by report type. |
@@ -34049,6 +34052,7 @@ Returns [`VulnerabilitySeveritiesCount`](#vulnerabilityseveritiescount).
| `image` | [`[String!]`](#string) | Filter vulnerabilities by location image. When this filter is present, the response only matches entries for a `reportType` that includes `container_scanning`, `cluster_image_scanning`. |
| `owaspTopTen` | [`[VulnerabilityOwaspTop10!]`](#vulnerabilityowasptop10) | Filter vulnerabilities by OWASP Top 10 2017 category. Wildcard value `NONE` is also supported but it cannot be combined with other OWASP top 10 values. |
| `owaspTopTen2021` {{< icon name="warning-solid" >}} | [`[VulnerabilityOwasp2021Top10!]`](#vulnerabilityowasp2021top10) | **Introduced** in GitLab 18.1. **Status**: Experiment. Filter vulnerabilities by OWASP Top 10 2021 category. Wildcard value `NONE` is also supported but it cannot be combined with other OWASP top 10 2021 values. To use this argument, you must have Elasticsearch configured and the `advanced_vulnerability_management` feature flag enabled. Not supported on Instance Security Dashboard queries. |
+| `policyViolations` {{< icon name="warning-solid" >}} | [`[PolicyViolations!]`](#policyviolations) | **Introduced** in GitLab 18.6. **Status**: Experiment. Filter by security policy violations. To use this argument, you must have Elasticsearch configured and the `advanced_vulnerability_management` feature flag enabled. Not supported on Instance Security Dashboard queries. |
| `projectId` | [`[ID!]`](#id) | Filter vulnerabilities by project. |
| `reachability` {{< icon name="warning-solid" >}} | [`ReachabilityType`](#reachabilitytype) | **Introduced** in GitLab 18.2. **Status**: Experiment. Filter vulnerabilities by reachability. |
| `reportType` | [`[VulnerabilityReportType!]`](#vulnerabilityreporttype) | Filter vulnerabilities by report type. |
@@ -41748,6 +41752,7 @@ four standard [pagination arguments](#pagination-arguments):
| `image` | [`[String!]`](#string) | Filter vulnerabilities by location image. When this filter is present, the response only matches entries for a `reportType` that includes `container_scanning`, `cluster_image_scanning`. |
| `owaspTopTen` | [`[VulnerabilityOwaspTop10!]`](#vulnerabilityowasptop10) | Filter vulnerabilities by OWASP Top 10 2017 category. Wildcard value `NONE` is also supported but it cannot be combined with other OWASP top 10 values. |
| `owaspTopTen2021` {{< icon name="warning-solid" >}} | [`[VulnerabilityOwasp2021Top10!]`](#vulnerabilityowasp2021top10) | **Introduced** in GitLab 18.1. **Status**: Experiment. Filter vulnerabilities by OWASP Top 10 2021 category. Wildcard value `NONE` is also supported but it cannot be combined with other OWASP top 10 2021 values. To use this argument, you must have Elasticsearch configured and the `advanced_vulnerability_management` feature flag enabled. Not supported on Instance Security Dashboard queries. |
+| `policyViolations` {{< icon name="warning-solid" >}} | [`[PolicyViolations!]`](#policyviolations) | **Introduced** in GitLab 18.6. **Status**: Experiment. Filter by security policy violations. To use this argument, you must have Elasticsearch configured and the `advanced_vulnerability_management` feature flag enabled. Not supported on Instance Security Dashboard queries. |
| `projectId` | [`[ID!]`](#id) | Filter vulnerabilities by project. |
| `reachability` {{< icon name="warning-solid" >}} | [`ReachabilityType`](#reachabilitytype) | **Introduced** in GitLab 18.2. **Status**: Experiment. Filter vulnerabilities by reachability. |
| `reportType` | [`[VulnerabilityReportType!]`](#vulnerabilityreporttype) | Filter vulnerabilities by report type. |
@@ -41832,6 +41837,7 @@ Returns [`VulnerabilitySeveritiesCount`](#vulnerabilityseveritiescount).
| `image` | [`[String!]`](#string) | Filter vulnerabilities by location image. When this filter is present, the response only matches entries for a `reportType` that includes `container_scanning`, `cluster_image_scanning`. |
| `owaspTopTen` | [`[VulnerabilityOwaspTop10!]`](#vulnerabilityowasptop10) | Filter vulnerabilities by OWASP Top 10 2017 category. Wildcard value `NONE` is also supported but it cannot be combined with other OWASP top 10 values. |
| `owaspTopTen2021` {{< icon name="warning-solid" >}} | [`[VulnerabilityOwasp2021Top10!]`](#vulnerabilityowasp2021top10) | **Introduced** in GitLab 18.1. **Status**: Experiment. Filter vulnerabilities by OWASP Top 10 2021 category. Wildcard value `NONE` is also supported but it cannot be combined with other OWASP top 10 2021 values. To use this argument, you must have Elasticsearch configured and the `advanced_vulnerability_management` feature flag enabled. Not supported on Instance Security Dashboard queries. |
+| `policyViolations` {{< icon name="warning-solid" >}} | [`[PolicyViolations!]`](#policyviolations) | **Introduced** in GitLab 18.6. **Status**: Experiment. Filter by security policy violations. To use this argument, you must have Elasticsearch configured and the `advanced_vulnerability_management` feature flag enabled. Not supported on Instance Security Dashboard queries. |
| `projectId` | [`[ID!]`](#id) | Filter vulnerabilities by project. |
| `reachability` {{< icon name="warning-solid" >}} | [`ReachabilityType`](#reachabilitytype) | **Introduced** in GitLab 18.2. **Status**: Experiment. Filter vulnerabilities by reachability. |
| `reportType` | [`[VulnerabilityReportType!]`](#vulnerabilityreporttype) | Filter vulnerabilities by report type. |
@@ -50732,6 +50738,12 @@ Types of security policy project created status.
| `RUNNING` | Represents a running policy violation. |
| `WARNING` | Represents a policy violation warning. |
+### `PolicyViolations`
+
+| Value | Description |
+| ----- | ----------- |
+| `DISMISSED_IN_MR` | Dismissed in Merge request bypass reason. |
+
### `PrincipalType`
Types of principal that can have secret permissions.
diff --git a/ee/app/finders/security/vulnerability_elastic_base_finder.rb b/ee/app/finders/security/vulnerability_elastic_base_finder.rb
index 14fbb26559255d0389d8cf168282bf6aeac74e23..5c5d3d337992d34bdf8e66f4cad4cd39e93ea894 100644
--- a/ee/app/finders/security/vulnerability_elastic_base_finder.rb
+++ b/ee/app/finders/security/vulnerability_elastic_base_finder.rb
@@ -77,6 +77,7 @@ def initialize_search_params
identifier_name: params[:identifier_name],
reachability: reachability,
validity_check: validity_check,
+ policy_violations: policy_violations,
sort: sort
}
end
@@ -142,5 +143,11 @@ def es_search_options
def root_ancestor_ids
[vulnerable.root_ancestor.id]
end
+
+ def policy_violations
+ return unless params[:policy_violations]
+
+ ::Security::PolicyViolations::VIOLATIONS_TYPES.slice(*params[:policy_violations]).values
+ end
end
end
diff --git a/ee/app/graphql/resolvers/vulnerabilities_resolver.rb b/ee/app/graphql/resolvers/vulnerabilities_resolver.rb
index 9e232ee3669d8582b188b69648884b0cb61c2f9e..b98b220fb199cdaf67db0996cfafe9ae3fd9887a 100644
--- a/ee/app/graphql/resolvers/vulnerabilities_resolver.rb
+++ b/ee/app/graphql/resolvers/vulnerabilities_resolver.rb
@@ -110,6 +110,14 @@ class VulnerabilitiesResolver < VulnerabilitiesBaseResolver
experiment: { milestone: '18.5' },
description: 'Filter vulnerabilities by validity check.'
+ argument :policy_violations, [::Types::SecurityOrchestration::PolicyViolationsEnum],
+ required: false,
+ experiment: { milestone: '18.6' },
+ description: 'Filter by security policy violations. ' \
+ 'To use this argument, you must have Elasticsearch configured and the ' \
+ '`advanced_vulnerability_management` feature flag enabled. ' \
+ 'Not supported on Instance Security Dashboard queries.'
+
def resolve_with_lookahead(**args)
return Vulnerability.none unless vulnerable&.feature_available?(:security_dashboard)
diff --git a/ee/app/graphql/resolvers/vulnerability_filterable.rb b/ee/app/graphql/resolvers/vulnerability_filterable.rb
index 672a1f1efe517790330f0e484428e698cc0d2b9d..48a47dbb9656df5084e61ab4e6e7ca6f1c5c2ed7 100644
--- a/ee/app/graphql/resolvers/vulnerability_filterable.rb
+++ b/ee/app/graphql/resolvers/vulnerability_filterable.rb
@@ -8,7 +8,7 @@ module VulnerabilityFilterable
private
- ADVANCED_FILTERS = [:owasp_top_10_2021, :identifier_name, :reachability, :validity_check].freeze
+ ADVANCED_FILTERS = [:owasp_top_10_2021, :identifier_name, :reachability, :validity_check, :policy_violations].freeze
def validate_filters(filters)
# identifier_name is also supported on postgres
@@ -19,6 +19,7 @@ def validate_filters(filters)
validate_reachability!(vulnerable) if filters[:reachability].present?
validate_validity_check!(vulnerable) if filters[:validity_check].present?
+ validate_policy_violations!(vulnerable) if filters[:policy_violations].present?
# Identifier validation should only run for
# 1. GitLab .com and Dedicated if ES is not available
@@ -90,5 +91,19 @@ def validate_validity_check!(vulnerable)
'The \'validity_check\' argument is not currently supported on security center dashboard or ' \
'the required migrations are not completed.'
end
+
+ def validate_policy_violations!(vulnerable)
+ group =
+ if vulnerable.is_a?(Project)
+ vulnerable.group
+ elsif vulnerable.is_a?(Group)
+ vulnerable
+ end
+
+ return if group && Feature.enabled?(:policy_violations_es_filter, group)
+
+ raise ::Gitlab::Graphql::Errors::ArgumentError,
+ 'The \'policy_violations\' argument is not currently supported on security center dashboard'
+ end
end
end
diff --git a/ee/app/graphql/resolvers/vulnerability_severities_count_resolver.rb b/ee/app/graphql/resolvers/vulnerability_severities_count_resolver.rb
index 6ca4bdcd851a3830e0118cfdecd55c53f6d60e2a..b2b5f84215c939fdeabe6c6b6092c0450a2c437b 100644
--- a/ee/app/graphql/resolvers/vulnerability_severities_count_resolver.rb
+++ b/ee/app/graphql/resolvers/vulnerability_severities_count_resolver.rb
@@ -107,6 +107,14 @@ class VulnerabilitySeveritiesCountResolver < VulnerabilitiesBaseResolver
experiment: { milestone: '18.5' },
description: 'Filter vulnerabilities by token status.'
+ argument :policy_violations, [::Types::SecurityOrchestration::PolicyViolationsEnum],
+ required: false,
+ experiment: { milestone: '18.6' },
+ description: 'Filter by security policy violations. ' \
+ 'To use this argument, you must have Elasticsearch configured and the ' \
+ '`advanced_vulnerability_management` feature flag enabled. ' \
+ 'Not supported on Instance Security Dashboard queries.'
+
def resolve(**args)
return Vulnerability.none unless vulnerable
diff --git a/ee/app/graphql/types/security_orchestration/policy_violations_enum.rb b/ee/app/graphql/types/security_orchestration/policy_violations_enum.rb
new file mode 100644
index 0000000000000000000000000000000000000000..0d8b71b3e20149fd045294a5986f3562aa7d9e7a
--- /dev/null
+++ b/ee/app/graphql/types/security_orchestration/policy_violations_enum.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+module Types
+ module SecurityOrchestration # rubocop:disable Gitlab/BoundedContexts -- Existing module
+ class PolicyViolationsEnum < BaseEnum
+ graphql_name 'PolicyViolations'
+
+ value 'DISMISSED_IN_MR',
+ description: 'Dismissed in Merge request bypass reason.',
+ value: :dismissed_in_mr
+ end
+ end
+end
diff --git a/ee/lib/search/elastic/vulnerability_filters.rb b/ee/lib/search/elastic/vulnerability_filters.rb
index 93adeaa2b0fad19bf4c3d35cd1517e5c63a959d6..c33dfa278594134dc2f07c063fe51e47acf1b4a1 100644
--- a/ee/lib/search/elastic/vulnerability_filters.rb
+++ b/ee/lib/search/elastic/vulnerability_filters.rb
@@ -433,6 +433,26 @@ def by_validity_check(query_hash:, options:)
end
end
+ def by_policy_violations(query_hash:, options:)
+ policy_violations = options[:policy_violations]
+ return query_hash if policy_violations.blank?
+
+ unless policy_violations.to_set.subset?(::Security::PolicyViolations::VIOLATIONS_TYPES.values.to_set)
+ return query_hash
+ end
+
+ context.name(:filters) do
+ add_filter(query_hash, :query, :bool, :filter) do
+ {
+ terms: {
+ _name: context.name(:policy_violations),
+ policy_violations: policy_violations
+ }
+ }
+ end
+ end
+ end
+
private
def valid_owasp_values?(owasp_values, regex_constant)
diff --git a/ee/lib/search/elastic/vulnerability_query_builder.rb b/ee/lib/search/elastic/vulnerability_query_builder.rb
index 81c703cee08273f598d8694db59f0f9e93a4d2ae..3f38aca86536a5a383d441362ec480a95ce85ccc 100644
--- a/ee/lib/search/elastic/vulnerability_query_builder.rb
+++ b/ee/lib/search/elastic/vulnerability_query_builder.rb
@@ -54,6 +54,11 @@ def build # rubocop:disable Metrics/AbcSize -- need all the filters in one place
)
end
+ if ::Elastic::DataMigrationService.migration_has_finished?(:add_policy_violations_field_to_vulnerability)
+ query_hash = ::Search::Elastic::VulnerabilityFilters.by_policy_violations(
+ query_hash: query_hash, options: options)
+ end
+
query_hash = ::Search::Elastic::VulnerabilityAggregations.by_severity_counts(
query_hash: query_hash, options: options)
query_hash = ::Search::Elastic::VulnerabilityAggregations.by_identifiers_search(
diff --git a/ee/spec/graphql/resolvers/vulnerabilities_resolver_spec.rb b/ee/spec/graphql/resolvers/vulnerabilities_resolver_spec.rb
index a47fe6dbd48fa29a79ba55a68e8761ac374b780e..91e48f3f13a46794f1d73911ccb4fb171ee04f9d 100644
--- a/ee/spec/graphql/resolvers/vulnerabilities_resolver_spec.rb
+++ b/ee/spec/graphql/resolvers/vulnerabilities_resolver_spec.rb
@@ -290,6 +290,17 @@
end
end
end
+
+ context 'when filtering vulnerabilities with policy_violations', :elastic do
+ let(:params) { { policy_violations: ['DISMISSED_IN_MR'] } }
+ let(:error_msg) { "Feature is not supported for InstanceSecurityDashboard" }
+
+ it 'raises an error' do
+ expect_graphql_error_to_be_created(Gitlab::Graphql::Errors::ArgumentError, s_(error_msg)) do
+ resolved
+ end
+ end
+ end
end
context 'when image is given' do
@@ -574,6 +585,64 @@ def create_vuln_with_status(severity:, status: nil)
end
end
+ context 'when filtering vulnerabilities with policy_violations', :elastic do
+ let(:params) { { policy_violations: ['DISMISSED_IN_MR'] } }
+
+ context 'without elasticsearch' do
+ before do
+ allow(::Search::Elastic::VulnerabilityIndexingHelper).to receive(:vulnerability_indexing_allowed?).and_return(false)
+ end
+
+ it_behaves_like 'raises ES errors'
+ end
+
+ context 'with advanced_vulnerability_management FF disabled' do
+ before do
+ allow(::Search::Elastic::VulnerabilityIndexingHelper).to receive(:vulnerability_indexing_allowed?).and_return(true)
+ stub_feature_flags(advanced_vulnerability_management: false)
+ end
+
+ it_behaves_like 'raises ES errors'
+ end
+
+ shared_examples_for 'when elasticsearch is available' do
+ let_it_be(:dismissed_vulnerability_read) { create(:vulnerability_read, project: project) }
+
+ let_it_be(:non_dismissed_vulnerability_read) { create(:vulnerability_read, project: project) }
+
+ before do
+ stub_ee_application_setting(elasticsearch_search: true, elasticsearch_indexing: true)
+
+ create(:policy_dismissal, :preserved, project: project, security_findings_uuids: [dismissed_vulnerability_read.uuid])
+
+ Elastic::ProcessBookkeepingService.track!(dismissed_vulnerability_read, non_dismissed_vulnerability_read)
+ ensure_elasticsearch_index!
+
+ allow(current_user).to receive(:can?).with(:access_advanced_vulnerability_management, vulnerable).and_return(true)
+ end
+
+ it 'only returns vulnerabilities with matching policy_violations types' do
+ expect(Gitlab::Search::Client).to receive(:execute_search).and_call_original
+
+ results = resolved.to_a
+
+ expect(results).to match_array([dismissed_vulnerability_read].map(&:vulnerability))
+ end
+ end
+
+ context 'when vulnerable is a project' do
+ let(:vulnerable) { project }
+
+ it_behaves_like 'when elasticsearch is available'
+ end
+
+ context 'when vulnerable is a group' do
+ let(:vulnerable) { group }
+
+ it_behaves_like 'when elasticsearch is available'
+ end
+ end
+
context 'when identifer_name is given' do
let_it_be(:identifier_name) { 'CVE-2024-1234' }
diff --git a/ee/spec/graphql/resolvers/vulnerability_severities_count_resolver_spec.rb b/ee/spec/graphql/resolvers/vulnerability_severities_count_resolver_spec.rb
index ad1bdc4156ae53484c19abb7549cf0730e2b1536..eba5f363e5ece0423d3f77cebdaa8f04188043c2 100644
--- a/ee/spec/graphql/resolvers/vulnerability_severities_count_resolver_spec.rb
+++ b/ee/spec/graphql/resolvers/vulnerability_severities_count_resolver_spec.rb
@@ -558,6 +558,32 @@ def create_vuln_with_status(severity:, status: nil)
end
end
end
+
+ context 'with policy_violations as parameter', :elastic do
+ let(:filters) { { policy_violations: ['DISMISSED_IN_MR'] } }
+ let(:expected_result) { { 'critical' => 1 } }
+ let_it_be(:dismissed_vulnerability_read) { create(:vulnerability_read, severity: :critical, project: project) }
+ let_it_be(:non_dismissed_vulnerability_read) { create(:vulnerability_read, severity: :low, project: project) }
+
+ before do
+ stub_ee_application_setting(elasticsearch_search: true, elasticsearch_indexing: true)
+
+ create(:policy_dismissal, :preserved, project: project, security_findings_uuids: [dismissed_vulnerability_read.uuid])
+
+ Elastic::ProcessBookkeepingService.track!(dismissed_vulnerability_read, non_dismissed_vulnerability_read)
+ ensure_elasticsearch_index!
+
+ allow(current_user).to receive(:can?).with(:admin_all_resources).and_call_original
+ allow(current_user).to receive(:can?)
+ .with(:access_advanced_vulnerability_management, vulnerable)
+ .and_return(true)
+ end
+
+ it 'only considers vulnerabilities with matching policy_violations values' do
+ expect(Gitlab::Search::Client).to receive(:execute_search).and_call_original
+ is_expected.to eq(expected_result)
+ end
+ end
end
context 'when resolving vulnerabilities for an instance security dashboard' do
diff --git a/ee/spec/graphql/types/security_orchestration/policy_violations_enum_spec.rb b/ee/spec/graphql/types/security_orchestration/policy_violations_enum_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..6c7738f43dc83ec53e96ebc4cb294765ba648cc4
--- /dev/null
+++ b/ee/spec/graphql/types/security_orchestration/policy_violations_enum_spec.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe GitlabSchema.types['PolicyViolations'], feature_category: :security_policy_management do
+ specify { expect(described_class.graphql_name).to eq('PolicyViolations') }
+
+ it 'exposes all policy violations types' do
+ expect(described_class.values.keys).to include(*%w[DISMISSED_IN_MR])
+ end
+end
diff --git a/ee/spec/lib/search/elastic/vulnerability_filters_spec.rb b/ee/spec/lib/search/elastic/vulnerability_filters_spec.rb
index 4a695face28d8c3369e93a40db57271bf5b66888..ef3d3fb56d0ffb52b46f8fdf914790ba46b48b8f 100644
--- a/ee/spec/lib/search/elastic/vulnerability_filters_spec.rb
+++ b/ee/spec/lib/search/elastic/vulnerability_filters_spec.rb
@@ -867,4 +867,45 @@
end
end
end
+
+ describe '.by_policy_violations' do
+ subject(:by_policy_violations) { described_class.by_policy_violations(query_hash: query_hash, options: options) }
+
+ context 'when options[:policy_violations] is empty' do
+ let(:options) { {} }
+
+ it_behaves_like 'does not modify the query_hash'
+
+ context 'with invalid by_policy_violations value' do
+ let(:options) { { policy_violations: [::Security::PolicyViolations::VIOLATIONS_TYPES.values.last + 1] } }
+
+ it_behaves_like 'does not modify the query_hash'
+ end
+
+ context 'when options[:policy_violations] contains a valid policy violation' do
+ let(:options) { { policy_violations: [::Security::PolicyViolations::VIOLATIONS_TYPES.each_value.first] } }
+ let(:expected_query) do
+ {
+ query: {
+ bool: {
+ filter: [{
+ terms: {
+ _name: "filters:policy_violations",
+ policy_violations: [0]
+ }
+ }],
+ must_not: [],
+ must: [],
+ should: []
+ }
+ }
+ }
+ end
+
+ it 'adds the policy_violations filter to query_hash' do
+ expect(by_policy_violations).to eq(expected_query)
+ end
+ end
+ end
+ end
end
diff --git a/ee/spec/lib/search/elastic/vulnerability_query_builder_spec.rb b/ee/spec/lib/search/elastic/vulnerability_query_builder_spec.rb
index 28ebd7d905a31f4350278c239938d6e73909b9c7..945176ff9b35918c8ccc0185fb850ff3e2082afc 100644
--- a/ee/spec/lib/search/elastic/vulnerability_query_builder_spec.rb
+++ b/ee/spec/lib/search/elastic/vulnerability_query_builder_spec.rb
@@ -293,6 +293,37 @@
end
end
+ describe 'policy_violations' do
+ let(:options) do
+ base_options.merge(policy_violations: [::Security::PolicyViolations::VIOLATIONS_TYPES[:dismissed_in_mr]])
+ end
+
+ context 'with finished migrations' do
+ before do
+ set_elasticsearch_migration_to(:add_policy_violations_field_to_vulnerability)
+ end
+
+ it 'does add filter' do
+ assert_names_in_query(build, with: %w[
+ filters:archived_projects
+ filters:policy_violations
+ ])
+ end
+ end
+
+ context 'without finished migrations' do
+ before do
+ set_elasticsearch_migration_to(:add_policy_violations_field_to_vulnerability, including: false)
+ end
+
+ it 'does not add reachability filter' do
+ assert_names_in_query(build, with: %w[
+ filters:archived_projects
+ ])
+ end
+ end
+ end
+
describe 'by_vulnerabilities_over_time' do
let(:current_day) { Time.current.beginning_of_day }
let(:current_day_minus_1) { current_day - 1.day }
diff --git a/ee/spec/support/shared_examples/graphql/resolvers/vulnerability_filterable_shared_examples.rb b/ee/spec/support/shared_examples/graphql/resolvers/vulnerability_filterable_shared_examples.rb
index b5bf249009f75081b6061c7a7fea715dd2238a47..3b421f2b4d772d1b077fd5d245b9a0366210ff70 100644
--- a/ee/spec/support/shared_examples/graphql/resolvers/vulnerability_filterable_shared_examples.rb
+++ b/ee/spec/support/shared_examples/graphql/resolvers/vulnerability_filterable_shared_examples.rb
@@ -54,6 +54,22 @@
end
end
end
+
+ context 'with policy_violations' do
+ let(filter_key) { { policy_violations: [Security::FindingTokenStatus.statuses.each_key.first.upcase] } }
+
+ context 'when `policy_violations_es_filter` feature flag is disabled' do
+ before do
+ stub_feature_flags(policy_violations_es_filter: false)
+ end
+
+ it 'raises an ArgumentError' do
+ expect_graphql_error_to_be_created(Gitlab::Graphql::Errors::ArgumentError) do
+ subject
+ end
+ end
+ end
+ end
end
end