Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGES/+default-push-repo.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Changed the default created repository on push to be a ContainerRepository instead of a ContainerPushRepository. ContainerPushRepository will eventually be phased out in future releases.
1 change: 1 addition & 0 deletions CHANGES/+rbac-rewrite.doc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Rewrote the RBAC documentation to be more comprehensive and detailed.
855 changes: 431 additions & 424 deletions docs/admin/learn/rbac.md

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion pulp_container/app/authorization.py
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,6 @@ def has_push_permissions(self, path):
if not domain:
return False

print("Checking push permissions for path ", path, "and domain ", domain.name)
try:
distribution = ContainerDistribution.objects.get(base_path=path, pulp_domain=domain)
except ContainerDistribution.DoesNotExist:
Expand Down
5 changes: 3 additions & 2 deletions pulp_container/app/global_access_conditions.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,10 @@ def has_namespace_obj_perms(request, view, action, permission):
if type(obj) is models.ContainerDistribution:
namespace = obj.namespace
return request.user.has_perm(permission, namespace)
elif type(obj) is models.ContainerPushRepository:
elif type(obj) is models.ContainerPushRepository or type(obj) is models.ContainerRepository:
for dist in obj.distributions.all():
if request.user.has_perm(permission, dist.cast().namespace):
namespace = dist.cast().namespace
if namespace and request.user.has_perm(permission, namespace):
return True
elif type(obj) is models.ContainerPullThroughDistribution:
namespace = obj.namespace
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Generated by Django 5.2.13 on 2026-06-03 19:16

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
('container', '0049_manifestsignature_fingerprint'),
]

operations = [
migrations.AlterModelOptions(
name='containernamespace',
options={'permissions': [('namespace_add_containerdistribution', 'Add any distribution to a namespace'), ('namespace_delete_containerdistribution', 'Delete any distribution from a namespace'), ('namespace_view_containerdistribution', 'View any distribution in a namespace'), ('namespace_pull_containerdistribution', 'Pull from any distribution in a namespace'), ('namespace_push_containerdistribution', 'Push to any distribution in a namespace'), ('namespace_change_containerdistribution', 'Change any distribution in a namespace'), ('namespace_view_containerpushrepository', 'View any push repository in a namespace'), ('namespace_view_containerrepository', 'View any repository in a namespace'), ('namespace_modify_content_containerpushrepository', 'Modify content in any push repository in a namespace'), ('namespace_modify_content_containerrepository', 'Modify content in any repository in a namespace'), ('namespace_change_containerpushrepository', 'Update any existing push repository in a namespace'), ('namespace_change_containerrepository', 'Change any repository in a namespace'), ('manage_roles_containernamespace', 'Can manage role assignments on container namespace')]},
),
]
2 changes: 2 additions & 0 deletions pulp_container/app/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,7 @@ class Meta:
("namespace_push_containerdistribution", "Push to any distribution in a namespace"),
("namespace_change_containerdistribution", "Change any distribution in a namespace"),
("namespace_view_containerpushrepository", "View any push repository in a namespace"),
("namespace_view_containerrepository", "View any repository in a namespace"),
(
"namespace_modify_content_containerpushrepository",
"Modify content in any push repository in a namespace",
Expand All @@ -470,6 +471,7 @@ class Meta:
"namespace_change_containerpushrepository",
"Update any existing push repository in a namespace",
),
("namespace_change_containerrepository", "Change any repository in a namespace"),
(
"manage_roles_containernamespace",
"Can manage role assignments on container namespace",
Expand Down
36 changes: 26 additions & 10 deletions pulp_container/app/registry_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,13 @@
from pulpcore.plugin import pulp_hashlib
from pulpcore.plugin.exceptions import TimeoutException
from pulpcore.plugin.files import PulpTemporaryUploadedFile
from pulpcore.plugin.models import Artifact, ContentArtifact, RemoteArtifact, UploadChunk
from pulpcore.plugin.models import (
Artifact,
ContentArtifact,
RemoteArtifact,
Repository,
UploadChunk,
)
from pulpcore.plugin.tasking import dispatch
from pulpcore.plugin.util import get_domain, get_objects_for_user, get_url

Expand Down Expand Up @@ -436,11 +442,9 @@ def get_dr_push(self, request, path, create=False):
repository = distribution.repository
if repository:
repository = repository.cast()
if not repository.PUSH_ENABLED:
raise RepositoryInvalid(name=path, message="Repository is read-only.")
elif create:
with transaction.atomic():
repository = serializers.ContainerPushRepositorySerializer.get_or_create(
repository = serializers.ContainerRepositorySerializer.get_or_create(
{"name": path, "pulp_domain": domain}
)
distribution.repository = repository
Expand All @@ -451,11 +455,22 @@ def get_dr_push(self, request, path, create=False):

def create_dr(self, path, request):
domain = get_domain()
repository_types = [
models.ContainerRepository.get_pulp_type(),
models.ContainerPushRepository.get_pulp_type(),
]
with transaction.atomic():
try:
repository = serializers.ContainerPushRepositorySerializer.get_or_create(
{"name": path, "pulp_domain": domain}
)
# Handle new default of ContainerRepository and fallback old ContainerPushRepository
repository = Repository.objects.filter(name=path, pulp_domain=domain).first()
if repository:
if repository.pulp_type not in repository_types:
raise RepositoryInvalid(name=path, message="Repository is read-only.")
repository = repository.cast()
else:
repository = serializers.ContainerRepositorySerializer.get_or_create(
{"name": path, "pulp_domain": domain}
)
distribution = serializers.ContainerDistributionSerializer.get_or_create(
{"base_path": path, "name": path, "pulp_domain": domain},
{"repository": get_url(repository)},
Expand All @@ -464,9 +479,10 @@ def create_dr(self, path, request):
raise RepositoryInvalid(name=path, message="Repository is read-only.")

if distribution.repository:
dist_repository = distribution.repository.cast()
if not dist_repository.PUSH_ENABLED or repository != dist_repository:
raise RepositoryInvalid(name=path, message="Repository is read-only.")
if repository.pk != distribution.repository.pk:
raise RepositoryInvalid(
name=path, message="Repository is not available for push."
)
else:
distribution.repository = repository
distribution.save()
Expand Down
9 changes: 5 additions & 4 deletions pulp_container/app/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ class Meta:
model = models.ContainerNamespace


class ContainerRepositorySerializer(RepositorySerializer):
class ContainerRepositorySerializer(RepositorySerializer, GetOrCreateSerializerMixin):
"""
Serializer for Container Repositories.
"""
Expand Down Expand Up @@ -984,12 +984,13 @@ def validate(self, data):
}
)

if repository.PUSH_ENABLED:
distro_count = repository.distributions.count()
if distro_count == 1:
if "future_base_path" in data:
raise serializers.ValidationError(
{
"future_base_path": _(
"This field cannot be set since this is a push repo type."
"This field cannot be set since this repo has a single distribution."
)
}
)
Expand All @@ -999,7 +1000,7 @@ def validate(self, data):
raise serializers.ValidationError(
{
"future_base_path": _(
"This field is required since this is a sync repo type."
"This field is required since this repo has zero or multiple distributions."
)
}
)
Expand Down
Loading
Loading