diff --git a/app/graphql/resolvers/project_container_registry_protection_rules_resolver.rb b/app/graphql/resolvers/project_container_registry_protection_rules_resolver.rb
new file mode 100644
index 0000000000000000000000000000000000000000..e051943ee5b96e05651623b01b36de5c325615e6
--- /dev/null
+++ b/app/graphql/resolvers/project_container_registry_protection_rules_resolver.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+module Resolvers
+ class ProjectContainerRegistryProtectionRulesResolver < BaseResolver
+ type Types::ContainerRegistry::Protection::RuleType.connection_type, null: true
+
+ alias_method :project, :object
+
+ def resolve(**_args)
+ return [] if Feature.disabled?(:container_registry_protected_containers, project)
+
+ project.container_registry_protection_rules
+ end
+ end
+end
diff --git a/app/graphql/types/project_type.rb b/app/graphql/types/project_type.rb
index 4ee6e2429b7e4d6aaaee16707bbc355b7e6c2fc6..05add3af1819e836cb957844de690466d5df6813 100644
--- a/app/graphql/types/project_type.rb
+++ b/app/graphql/types/project_type.rb
@@ -496,6 +496,13 @@ class ProjectType < BaseObject
null: true,
description: 'Container expiration policy of the project.'
+ field :container_registry_protection_rules,
+ Types::ContainerRegistry::Protection::RuleType.connection_type,
+ null: true,
+ description: 'Container protection rules for the project.',
+ alpha: { milestone: '16.10' },
+ resolver: Resolvers::ProjectContainerRegistryProtectionRulesResolver
+
field :container_repositories, Types::ContainerRepositoryType.connection_type,
null: true,
description: 'Container repositories of the project.',
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index e90412c9e84e8d5b80953f569fd87fa4f9fc19c2..722deb02095612589602163f0377c131f812da57 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -10450,6 +10450,29 @@ The edge type for [`ConnectedAgent`](#connectedagent).
| `cursor` | [`String!`](#string) | A cursor for use in pagination. |
| `node` | [`ConnectedAgent`](#connectedagent) | The item at the end of the edge. |
+#### `ContainerRegistryProtectionRuleConnection`
+
+The connection type for [`ContainerRegistryProtectionRule`](#containerregistryprotectionrule).
+
+##### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| `edges` | [`[ContainerRegistryProtectionRuleEdge]`](#containerregistryprotectionruleedge) | A list of edges. |
+| `nodes` | [`[ContainerRegistryProtectionRule]`](#containerregistryprotectionrule) | A list of nodes. |
+| `pageInfo` | [`PageInfo!`](#pageinfo) | Information to aid in pagination. |
+
+#### `ContainerRegistryProtectionRuleEdge`
+
+The edge type for [`ContainerRegistryProtectionRule`](#containerregistryprotectionrule).
+
+##### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| `cursor` | [`String!`](#string) | A cursor for use in pagination. |
+| `node` | [`ContainerRegistryProtectionRule`](#containerregistryprotectionrule) | The item at the end of the edge. |
+
#### `ContainerRepositoryConnection`
The connection type for [`ContainerRepository`](#containerrepository).
@@ -25268,6 +25291,7 @@ Check permissions for the current user on a vulnerability finding.
| `complianceFrameworks` | [`ComplianceFrameworkConnection`](#complianceframeworkconnection) | Compliance frameworks associated with the project. (see [Connections](#connections)) |
| `containerExpirationPolicy` | [`ContainerExpirationPolicy`](#containerexpirationpolicy) | Container expiration policy of the project. |
| `containerRegistryEnabled` | [`Boolean`](#boolean) | Indicates if Container Registry is enabled for the current user. |
+| `containerRegistryProtectionRules` **{warning-solid}** | [`ContainerRegistryProtectionRuleConnection`](#containerregistryprotectionruleconnection) | **Introduced** in GitLab 16.10. **Status**: Experiment. Container protection rules for the project. |
| `containerRepositoriesCount` | [`Int!`](#int) | Number of container repositories in the project. |
| `corpuses` | [`CoverageFuzzingCorpusConnection`](#coveragefuzzingcorpusconnection) | Find corpuses of the project. (see [Connections](#connections)) |
| `createdAt` | [`Time`](#time) | Timestamp of the project creation. |
diff --git a/spec/requests/api/graphql/project/container_registry_protection_rules_spec.rb b/spec/requests/api/graphql/project/container_registry_protection_rules_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..57c50e4c33bc240db9f5b2cc0bfedd182907ffb0
--- /dev/null
+++ b/spec/requests/api/graphql/project/container_registry_protection_rules_spec.rb
@@ -0,0 +1,86 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'getting the containers protection rules linked to a project', :aggregate_failures, feature_category: :container_registry do
+ include GraphqlHelpers
+
+ let_it_be_with_reload(:project) { create(:project) }
+ let_it_be(:user) { project.owner }
+
+ let(:query) do
+ graphql_query_for(
+ :project,
+ { full_path: project.full_path },
+ query_nodes(:containerRegistryProtectionRules, of: 'ContainerRegistryProtectionRule')
+ )
+ end
+
+ let(:protection_rules) { graphql_data_at(:project, :containerRegistryProtectionRules, :nodes) }
+
+ subject(:send_graqhql_query) { post_graphql(query, current_user: user) }
+
+ context 'with authorized user owner' do
+ before do
+ send_graqhql_query
+ end
+
+ context 'with container protection rule' do
+ let_it_be(:container_protection_rule) { create(:container_registry_protection_rule, project: project) }
+
+ it_behaves_like 'a working graphql query'
+
+ it 'returns only on containersProtectionRule' do
+ expect(protection_rules.count).to eq 1
+ end
+
+ it 'returns all containers protection rule fields' do
+ expect(protection_rules).to include(
+ hash_including(
+ 'repositoryPathPattern' => container_protection_rule.repository_path_pattern,
+ 'pushProtectedUpToAccessLevel' => 'DEVELOPER',
+ 'deleteProtectedUpToAccessLevel' => 'DEVELOPER'
+ )
+ )
+ end
+ end
+
+ context 'without container protection rule' do
+ it_behaves_like 'a working graphql query'
+
+ it 'returns no containersProtectionRule' do
+ expect(protection_rules).to be_empty
+ end
+ end
+ end
+
+ context 'with unauthorized user' do
+ let_it_be(:user) { create(:user).tap { |u| project.add_developer(u) } }
+
+ before do
+ send_graqhql_query
+ end
+
+ it_behaves_like 'a working graphql query'
+
+ it 'returns no container protection rules' do
+ expect(protection_rules).to be_empty
+ end
+ end
+
+ context "when feature flag ':containers_protected_containers' disabled" do
+ let_it_be(:container_protection_rule) { create(:container_registry_protection_rule, project: project) }
+
+ before do
+ stub_feature_flags(container_registry_protected_containers: false)
+
+ send_graqhql_query
+ end
+
+ it_behaves_like 'a working graphql query'
+
+ it 'returns no container protection rules' do
+ expect(protection_rules).to be_empty
+ end
+ end
+end