Skip to content
代码片段 群组 项目
未验证 提交 b18810e6 编辑于 作者: Adie (she/her)'s avatar Adie (she/her) 提交者: GitLab
浏览文件

Add container tag protection rules to project

This allows the tag protection rules to be fetched
via the project.

Changelog: added
上级 622c940b
No related branches found
No related tags found
无相关合并请求
# frozen_string_literal: true
module Types
module ContainerRegistry
module Protection
class TagRuleAccessLevelEnum < BaseEnum
graphql_name 'ContainerProtectionTagRuleAccessLevel'
description 'Access level of a container registry tag protection rule resource'
::ContainerRegistry::Protection::TagRule::ACCESS_LEVELS.each_key do |access_level_key|
access_level_key = access_level_key.to_s
value access_level_key.upcase,
value: access_level_key,
experiment: { milestone: '17.8' },
description: "#{access_level_key.capitalize} access."
end
end
end
end
end
# frozen_string_literal: true
module Types
module ContainerRegistry
module Protection
class TagRuleType < ::Types::BaseObject
graphql_name 'ContainerProtectionTagRule'
description 'A container repository tag protection rule designed to prevent users with a certain ' \
'access level or lower from altering the container registry.'
authorize :admin_container_image
field :id,
::Types::GlobalIDType[::ContainerRegistry::Protection::TagRule],
null: false,
experiment: { milestone: '17.8' },
description: 'ID of the container repository tag protection rule.'
field :tag_name_pattern,
GraphQL::Types::String,
null: false,
experiment: { milestone: '17.8' },
description:
'Container repository tag name pattern protected by the protection rule. ' \
'For example, `v1.*`. Wildcard character `*` allowed.'
# rubocop:disable GraphQL/ExtractType -- These are stored as separate fields
field :minimum_access_level_for_delete,
Types::ContainerRegistry::Protection::TagRuleAccessLevelEnum,
null: true,
experiment: { milestone: '17.8' },
description:
'Minimum GitLab access level required to delete container image tags from the container repository. ' \
'For example, `MAINTAINER`, `OWNER`, or `ADMIN`. ' \
'If the value is `nil`, the minimum access level is ignored. ' \
'Users with at least the Developer role can delete container image tags.'
field :minimum_access_level_for_push,
Types::ContainerRegistry::Protection::TagRuleAccessLevelEnum,
null: true,
experiment: { milestone: '17.8' },
description:
'Minimum GitLab access level required to push container image tags to the container repository. ' \
'For example, `MAINTAINER`, `OWNER`, or `ADMIN`. ' \
'If the value is `nil`, the minimum access level is ignored. ' \
'Users with at least the Developer role can push container image tags.'
# rubocop:enable GraphQL/ExtractType -- These are stored as user preferences
end
end
end
end
......@@ -529,6 +529,13 @@ class ProjectType < BaseObject
experiment: { milestone: '16.10' },
resolver: Resolvers::ProjectContainerRegistryProtectionRulesResolver
field :container_protection_tag_rules,
Types::ContainerRegistry::Protection::TagRuleType.connection_type,
null: true,
experiment: { milestone: '17.8' },
description: 'Container repository tag protection rules for the project. ' \
'Returns an empty array if the `container_registry_protected_tags` feature flag is disabled.'
field :container_repositories, Types::ContainerRegistry::ContainerRepositoryType.connection_type,
null: true,
description: 'Container repositories of the project.',
......@@ -939,6 +946,12 @@ def organization_edit_path
)
end
def container_protection_tag_rules
return [] unless Feature.enabled?(:container_registry_protected_tags, object)
object.container_registry_protection_tag_rules
end
private
def project
......
# frozen_string_literal: true
module ContainerRegistry
module Protection
class TagRulePolicy < BasePolicy
delegate { @subject.project }
end
end
end
......@@ -13269,6 +13269,29 @@ The edge type for [`ContainerProtectionRepositoryRule`](#containerprotectionrepo
| <a id="containerprotectionrepositoryruleedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
| <a id="containerprotectionrepositoryruleedgenode"></a>`node` | [`ContainerProtectionRepositoryRule`](#containerprotectionrepositoryrule) | The item at the end of the edge. |
 
#### `ContainerProtectionTagRuleConnection`
The connection type for [`ContainerProtectionTagRule`](#containerprotectiontagrule).
##### Fields
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="containerprotectiontagruleconnectionedges"></a>`edges` | [`[ContainerProtectionTagRuleEdge]`](#containerprotectiontagruleedge) | A list of edges. |
| <a id="containerprotectiontagruleconnectionnodes"></a>`nodes` | [`[ContainerProtectionTagRule]`](#containerprotectiontagrule) | A list of nodes. |
| <a id="containerprotectiontagruleconnectionpageinfo"></a>`pageInfo` | [`PageInfo!`](#pageinfo) | Information to aid in pagination. |
#### `ContainerProtectionTagRuleEdge`
The edge type for [`ContainerProtectionTagRule`](#containerprotectiontagrule).
##### Fields
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="containerprotectiontagruleedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
| <a id="containerprotectiontagruleedgenode"></a>`node` | [`ContainerProtectionTagRule`](#containerprotectiontagrule) | The item at the end of the edge. |
#### `ContainerRepositoryConnection`
 
The connection type for [`ContainerRepository`](#containerrepository).
......@@ -21504,6 +21527,19 @@ A container repository protection rule designed to prevent users with a certain
| <a id="containerprotectionrepositoryruleminimumaccesslevelforpush"></a>`minimumAccessLevelForPush` **{warning-solid}** | [`ContainerProtectionRepositoryRuleAccessLevel`](#containerprotectionrepositoryruleaccesslevel) | **Introduced** in GitLab 16.6. **Status**: Experiment. Minimum GitLab access level required to push container images to the container repository. For example, `MAINTAINER`, `OWNER`, or `ADMIN`. If the value is `nil`, the minimum access level is ignored. Users with at least the Developer role can push container images. |
| <a id="containerprotectionrepositoryrulerepositorypathpattern"></a>`repositoryPathPattern` **{warning-solid}** | [`String!`](#string) | **Introduced** in GitLab 16.6. **Status**: Experiment. Container repository path pattern protected by the protection rule. For example, `my-project/my-container-*`. Wildcard character `*` allowed. |
 
### `ContainerProtectionTagRule`
A container repository tag protection rule designed to prevent users with a certain access level or lower from altering the container registry.
#### Fields
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="containerprotectiontagruleid"></a>`id` **{warning-solid}** | [`ContainerRegistryProtectionTagRuleID!`](#containerregistryprotectiontagruleid) | **Introduced** in GitLab 17.8. **Status**: Experiment. ID of the container repository tag protection rule. |
| <a id="containerprotectiontagruleminimumaccesslevelfordelete"></a>`minimumAccessLevelForDelete` **{warning-solid}** | [`ContainerProtectionTagRuleAccessLevel`](#containerprotectiontagruleaccesslevel) | **Introduced** in GitLab 17.8. **Status**: Experiment. Minimum GitLab access level required to delete container image tags from the container repository. For example, `MAINTAINER`, `OWNER`, or `ADMIN`. If the value is `nil`, the minimum access level is ignored. Users with at least the Developer role can delete container image tags. |
| <a id="containerprotectiontagruleminimumaccesslevelforpush"></a>`minimumAccessLevelForPush` **{warning-solid}** | [`ContainerProtectionTagRuleAccessLevel`](#containerprotectiontagruleaccesslevel) | **Introduced** in GitLab 17.8. **Status**: Experiment. Minimum GitLab access level required to push container image tags to the container repository. For example, `MAINTAINER`, `OWNER`, or `ADMIN`. If the value is `nil`, the minimum access level is ignored. Users with at least the Developer role can push container image tags. |
| <a id="containerprotectiontagruletagnamepattern"></a>`tagNamePattern` **{warning-solid}** | [`String!`](#string) | **Introduced** in GitLab 17.8. **Status**: Experiment. Container repository tag name pattern protected by the protection rule. For example, `v1.*`. Wildcard character `*` allowed. |
### `ContainerRepository`
 
A container repository.
......@@ -31462,6 +31498,7 @@ Project-level settings for product analytics provider.
| <a id="projectcomponentusages"></a>`componentUsages` | [`CiCatalogResourceComponentUsageConnection`](#cicatalogresourcecomponentusageconnection) | Component(s) used by the project. (see [Connections](#connections)) |
| <a id="projectcontainerexpirationpolicy"></a>`containerExpirationPolicy` **{warning-solid}** | [`ContainerExpirationPolicy`](#containerexpirationpolicy) | **Deprecated** in GitLab 17.5. Use `container_tags_expiration_policy`. |
| <a id="projectcontainerprotectionrepositoryrules"></a>`containerProtectionRepositoryRules` **{warning-solid}** | [`ContainerProtectionRepositoryRuleConnection`](#containerprotectionrepositoryruleconnection) | **Introduced** in GitLab 16.10. **Status**: Experiment. Container protection rules for the project. |
| <a id="projectcontainerprotectiontagrules"></a>`containerProtectionTagRules` **{warning-solid}** | [`ContainerProtectionTagRuleConnection`](#containerprotectiontagruleconnection) | **Introduced** in GitLab 17.8. **Status**: Experiment. Container repository tag protection rules for the project. Returns an empty array if the `container_registry_protected_tags` feature flag is disabled. |
| <a id="projectcontainerregistryenabled"></a>`containerRegistryEnabled` | [`Boolean`](#boolean) | Indicates if Container Registry is enabled for the current user. |
| <a id="projectcontainerrepositoriescount"></a>`containerRepositoriesCount` | [`Int!`](#int) | Number of container repositories in the project. |
| <a id="projectcontainertagsexpirationpolicy"></a>`containerTagsExpirationPolicy` | [`ContainerTagsExpirationPolicy`](#containertagsexpirationpolicy) | Container tags expiration policy of the project. |
......@@ -38833,6 +38870,16 @@ Access level of a container registry protection rule resource.
| <a id="containerprotectionrepositoryruleaccesslevelmaintainer"></a>`MAINTAINER` **{warning-solid}** | **Introduced** in GitLab 16.6. **Status**: Experiment. Maintainer access. |
| <a id="containerprotectionrepositoryruleaccesslevelowner"></a>`OWNER` **{warning-solid}** | **Introduced** in GitLab 16.6. **Status**: Experiment. Owner access. |
 
### `ContainerProtectionTagRuleAccessLevel`
Access level of a container registry tag protection rule resource.
| Value | Description |
| ----- | ----------- |
| <a id="containerprotectiontagruleaccessleveladmin"></a>`ADMIN` **{warning-solid}** | **Introduced** in GitLab 17.8. **Status**: Experiment. Admin access. |
| <a id="containerprotectiontagruleaccesslevelmaintainer"></a>`MAINTAINER` **{warning-solid}** | **Introduced** in GitLab 17.8. **Status**: Experiment. Maintainer access. |
| <a id="containerprotectiontagruleaccesslevelowner"></a>`OWNER` **{warning-solid}** | **Introduced** in GitLab 17.8. **Status**: Experiment. Owner access. |
### `ContainerRepositoryCleanupStatus`
 
Status of the tags cleanup of a container repository.
......@@ -41920,6 +41967,12 @@ A `ContainerRegistryProtectionRuleID` is a global ID. It is encoded as a string.
 
An example `ContainerRegistryProtectionRuleID` is: `"gid://gitlab/ContainerRegistry::Protection::Rule/1"`.
 
### `ContainerRegistryProtectionTagRuleID`
A `ContainerRegistryProtectionTagRuleID` is a global ID. It is encoded as a string.
An example `ContainerRegistryProtectionTagRuleID` is: `"gid://gitlab/ContainerRegistry::Protection::TagRule/1"`.
### `ContainerRepositoryID`
 
A `ContainerRepositoryID` is a global ID. It is encoded as a string.
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe GitlabSchema.types['ContainerProtectionTagRuleAccessLevel'], feature_category: :container_registry do
it 'exposes all options' do
expect(described_class.values.keys).to match_array(%w[MAINTAINER OWNER ADMIN])
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe GitlabSchema.types['ContainerProtectionTagRule'], feature_category: :container_registry do
specify { expect(described_class.graphql_name).to eq('ContainerProtectionTagRule') }
specify { expect(described_class.description).to be_present }
specify { expect(described_class).to require_graphql_authorizations(:admin_container_image) }
describe 'id' do
subject { described_class.fields['id'] }
it { is_expected.to have_non_null_graphql_type(::Types::GlobalIDType[::ContainerRegistry::Protection::TagRule]) }
end
describe 'tag_name_pattern' do
subject { described_class.fields['tagNamePattern'] }
it { is_expected.to have_non_null_graphql_type(GraphQL::Types::String) }
end
describe 'minimum_access_level_for_push' do
subject { described_class.fields['minimumAccessLevelForPush'] }
it { is_expected.to have_nullable_graphql_type(Types::ContainerRegistry::Protection::TagRuleAccessLevelEnum) }
end
describe 'minimum_access_level_for_delete' do
subject { described_class.fields['minimumAccessLevelForDelete'] }
it { is_expected.to have_nullable_graphql_type(Types::ContainerRegistry::Protection::TagRuleAccessLevelEnum) }
end
end
......@@ -45,7 +45,7 @@
incident_management_timeline_event_tags visible_forks inherited_ci_variables autocomplete_users
ci_cd_settings detailed_import_status value_streams ml_models
allows_multiple_merge_request_assignees allows_multiple_merge_request_reviewers is_forked
protectable_branches available_deploy_keys explore_catalog_path
protectable_branches available_deploy_keys explore_catalog_path container_protection_tag_rules
]
expect(described_class).to include_graphql_fields(*expected_fields)
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'getting the container tag 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(:containerProtectionTagRules, of: 'ContainerProtectionTagRule')
)
end
let(:protection_rules) { graphql_data_at(:project, :containerProtectionTagRules, :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 tag protection rule' do
let_it_be(:tag_protection_rule) { create(:container_registry_protection_tag_rule, project: project) }
it_behaves_like 'a working graphql query'
it 'returns exactly one containersProtectionTagRule' do
expect(protection_rules.count).to eq 1
end
it 'returns all container tag protection rule fields' do
expect(protection_rules).to include(
hash_including(
'tagNamePattern' => tag_protection_rule.tag_name_pattern,
'minimumAccessLevelForDelete' => 'MAINTAINER',
'minimumAccessLevelForPush' => 'MAINTAINER'
)
)
end
end
context 'without container tag protection rule' do
it_behaves_like 'a working graphql query'
it 'returns no containersProtectionTagRule' do
expect(protection_rules).to be_empty
end
end
end
context 'with unauthorized user' do
let_it_be(:user) { create(:user, developer_of: project) }
before do
send_graqhql_query
end
it_behaves_like 'a working graphql query'
it 'returns no container tag protection rules' do
expect(protection_rules).to be_empty
end
end
context "when feature flag ':container_registry_protected_tags' disabled" do
let_it_be(:tag_protection_rule) { create(:container_registry_protection_tag_rule, project: project) }
before do
stub_feature_flags(container_registry_protected_tags: false)
send_graqhql_query
end
it_behaves_like 'a working graphql query'
it 'returns no container tag protection rules' do
expect(protection_rules).to be_empty
end
end
end
0% 加载中 .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册