pulp-container 2.28.0__tar.gz → 2.29.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pulp_container-2.28.0 → pulp_container-2.29.0}/CHANGES.md +134 -2
- {pulp_container-2.28.0 → pulp_container-2.29.0}/MANIFEST.in +4 -2
- {pulp_container-2.28.0 → pulp_container-2.29.0}/PKG-INFO +2 -2
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/__init__.py +1 -1
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/authorization.py +1 -2
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/exceptions.py +33 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/global_access_conditions.py +3 -2
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/json_schemas.py +1 -0
- pulp_container-2.29.0/pulp_container/app/migrations/0050_alter_containernamespace_options.py +17 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/models.py +3 -3
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/registry_api.py +119 -19
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/serializers.py +11 -4
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/tasks/__init__.py +1 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/tasks/builder.py +5 -4
- pulp_container-2.29.0/pulp_container/app/tasks/migrate_push_repository.py +133 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/tasks/sync_stages.py +35 -10
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/utils.py +19 -3
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/viewsets.py +184 -122
- pulp_container-2.29.0/pulp_container/tests/functional/api/test_cancel_blob_upload.py +71 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/tests/functional/api/test_content_cache.py +1 -1
- pulp_container-2.29.0/pulp_container/tests/functional/api/test_delete_blob.py +123 -0
- pulp_container-2.29.0/pulp_container/tests/functional/api/test_delete_manifest.py +97 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/tests/functional/api/test_domains.py +22 -4
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/tests/functional/api/test_flatpak.py +2 -2
- pulp_container-2.29.0/pulp_container/tests/functional/api/test_migrate_push_repository.py +181 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/tests/functional/api/test_pull_content.py +40 -1
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/tests/functional/api/test_push_content.py +83 -18
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/tests/functional/api/test_push_signatures.py +2 -2
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/tests/functional/api/test_rbac_push_repositories.py +86 -2
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/tests/functional/api/test_rbac_repo_content.py +32 -39
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/tests/functional/api/test_rbac_repo_versions.py +71 -3
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/tests/functional/api/test_recursive_remove.py +9 -2
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/tests/functional/api/test_sign_manifests.py +3 -3
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/tests/functional/api/test_tagging_images.py +2 -2
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/tests/functional/conftest.py +31 -0
- pulp_container-2.29.0/pulp_container/tests/unit/fixtures/ryuk_0.13.0_manifest_list.json +154 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/tests/unit/test_json_schemas.py +29 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container.egg-info/PKG-INFO +2 -2
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container.egg-info/SOURCES.txt +8 -1
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container.egg-info/requires.txt +1 -1
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pyproject.toml +5 -4
- {pulp_container-2.28.0 → pulp_container-2.29.0}/COMMITMENT +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/COPYRIGHT +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/LICENSE +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/README.rst +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/functest_requirements.txt +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/__init__.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/access_policy.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/cache.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/checks.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/content.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/downloaders.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/dynaconf_hooks.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/fields.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/management/__init__.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/management/commands/__init__.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/management/commands/container-handle-image-data.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/management/commands/container-repair-media-type.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/migrations/0001_initial.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/migrations/0001_squashed_0032_upload_artifact.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/migrations/0002_containerrepository.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/migrations/0003_oci_mediatype.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/migrations/0004_upload.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/migrations/0005_contentredirectcontentguard.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/migrations/0006_containerpushrepository.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/migrations/0007_clear_tags_artifacts_refs.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/migrations/0008_include_exclude_tags.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/migrations/0009_container_namespace.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/migrations/0010_remove_uploadchunk.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/migrations/0011_add_container_repository_permissions.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/migrations/0012_add_container_namespace_permissions.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/migrations/0013_add_pull_push_permissions.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/migrations/0014_containerdistribution_private.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/migrations/0015_manage_tags_push_repo.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/migrations/0016_add_delete_versions_permission.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/migrations/0017_add_granular_perms.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/migrations/0018_containerdistribution_description.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/migrations/0019_DATA_distribution_model_swap.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/migrations/0020_update_push_repo_perms.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/migrations/0021_data_move_redirect_content_guard_to_core.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/migrations/0022_delete_contentredirectcontentguard.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/migrations/0023_manifestsignature.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/migrations/0024_containerremote_sigstore.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/migrations/0025_signature_stored_in_textfield.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/migrations/0026_manifest_signing_service.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/migrations/0027_data_translate_perms_to_roles.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/migrations/0028_add_role_manage_permissions.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/migrations/0029_remove_blob_media_type.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/migrations/0030_enforce_tagged_manifest_reference.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/migrations/0031_replace_charf_with_textf.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/migrations/0032_upload_artifact.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/migrations/0033_raise_warning_for_repair.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/migrations/0034_translate_signed_schema.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/migrations/0035_alter_blob_content_ptr_and_more.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/migrations/0036_containerpushrepository_pending_blobs_manifests.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/migrations/0037_create_pull_through_cache_models.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/migrations/0038_add_manifest_metadata_fields.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/migrations/0039_manifest_data.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/migrations/0040_add_remote_repo_filter.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/migrations/0041_add_pull_through_pull_permissions.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/migrations/0042_add_manifest_nature_field.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/migrations/0043_add_os_arch_image_size_manifest_fields.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/migrations/0044_add_domain.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/migrations/0045_alter_manifest_compressed_image_size.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/migrations/0046_alter_manifest_listed_manifests.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/migrations/0047_containernamespace_pulp_labels.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/migrations/0048_containerremote_includes_excludes.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/migrations/0049_manifestsignature_fingerprint.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/migrations/__init__.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/modelresource.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/redirects.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/registry.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/replica.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/settings.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/tasks/download_image_data.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/tasks/recursive_add.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/tasks/recursive_remove.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/tasks/sign.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/tasks/synchronize.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/tasks/tag.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/tasks/untag.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/token_verification.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/urls.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/webserver_snippets/__init__.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/webserver_snippets/apache.conf +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/webserver_snippets/nginx.conf +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/constants.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/tests/__init__.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/tests/functional/__init__.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/tests/functional/api/__init__.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/tests/functional/api/test_build_images.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/tests/functional/api/test_crud_distributions.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/tests/functional/api/test_crud_remotes.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/tests/functional/api/test_pull_through_cache.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/tests/functional/api/test_pulpimportexport.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/tests/functional/api/test_rbac_remotes.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/tests/functional/api/test_rbac_sync_repositories.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/tests/functional/api/test_recursive_add.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/tests/functional/api/test_remote_filter_pull_through.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/tests/functional/api/test_repositories_list.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/tests/functional/api/test_sync.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/tests/functional/api/test_sync_signatures.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/tests/functional/api/test_token_authentication.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/tests/functional/constants.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/tests/functional/utils.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/tests/unit/__init__.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/tests/unit/test_models.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/tests/unit/test_serializers.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/tests/unit/test_sync_stages.py +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container.egg-info/dependency_links.txt +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container.egg-info/entry_points.txt +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container.egg-info/top_level.txt +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/setup.cfg +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/test_requirements.txt +0 -0
- {pulp_container-2.28.0 → pulp_container-2.29.0}/unittest_requirements.txt +0 -0
|
@@ -8,6 +8,45 @@
|
|
|
8
8
|
|
|
9
9
|
[//]: # (towncrier release notes start)
|
|
10
10
|
|
|
11
|
+
## 2.29.0 (2026-08-10) {: #2.29.0 }
|
|
12
|
+
|
|
13
|
+
#### Features {: #2.29.0-feature }
|
|
14
|
+
|
|
15
|
+
- Enable DELETE on the Docker v2 manifest endpoint so users can delete manifests by digest.
|
|
16
|
+
[#480](https://github.com/pulp/pulp_container/issues/480)
|
|
17
|
+
- Enable DELETE on the Docker v2 blob endpoint so users can delete blobs by digest.
|
|
18
|
+
[#481](https://github.com/pulp/pulp_container/issues/481)
|
|
19
|
+
- Added support for retrieving blob upload status via `GET /v2/<name>/blobs/uploads/<uuid>`.
|
|
20
|
+
[#483](https://github.com/pulp/pulp_container/issues/483)
|
|
21
|
+
- Added a `migrate` endpoint on push repositories that converts a legacy `ContainerPushRepository`
|
|
22
|
+
into a `ContainerRepository` in place. The repository primary key and version history are
|
|
23
|
+
preserved; only the repository type changes.
|
|
24
|
+
- Added support for cancelling blob uploads via `DELETE /v2/<name>/blobs/uploads/<uuid>`.
|
|
25
|
+
- Changed the default created repository on push to be a ContainerRepository instead of a ContainerPushRepository. ContainerPushRepository will eventually be phased out in future releases.
|
|
26
|
+
|
|
27
|
+
#### Bugfixes {: #2.29.0-bugfix }
|
|
28
|
+
|
|
29
|
+
- Fixed tag-based manifest pulls returning 404 when the client's `Accept` header listed the tagged manifest's media type together with parameters such as q-values, since the media type comparison did not strip them and had no support for the `*/*` wildcard.
|
|
30
|
+
[#2417](https://github.com/pulp/pulp_container/issues/2417)
|
|
31
|
+
- Add transparent repair code during Manifest sync to redownload the raw data in case it was lost during an upgrade.
|
|
32
|
+
- Added OCI manifest as an allowed media type in the Docker manifest list schema.
|
|
33
|
+
- Raised a proper `PulpException` subclass instead of a bare `Exception` when building or pushing an OCI image fails, so the error is not sanitized away by pulpcore in a future release.
|
|
34
|
+
|
|
35
|
+
#### Improved Documentation {: #2.29.0-doc }
|
|
36
|
+
|
|
37
|
+
- Rewrote the RBAC documentation to be more comprehensive and detailed.
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## 2.28.1 (2026-07-22) {: #2.28.1 }
|
|
42
|
+
|
|
43
|
+
#### Bugfixes {: #2.28.1-bugfix }
|
|
44
|
+
|
|
45
|
+
- Add transparent repair code during Manifest sync to redownload the raw data in case it was lost during an upgrade.
|
|
46
|
+
- Added OCI manifest as an allowed media type in the Docker manifest list schema.
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
11
50
|
## 2.28.0 (2026-05-29) {: #2.28.0 }
|
|
12
51
|
|
|
13
52
|
#### Features {: #2.28.0-feature }
|
|
@@ -59,6 +98,21 @@
|
|
|
59
98
|
|
|
60
99
|
---
|
|
61
100
|
|
|
101
|
+
## 2.27.11 (2026-07-29) {: #2.27.11 }
|
|
102
|
+
|
|
103
|
+
No significant changes.
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## 2.27.10 (2026-06-08) {: #2.27.10 }
|
|
108
|
+
|
|
109
|
+
#### Bugfixes {: #2.27.10-bugfix }
|
|
110
|
+
|
|
111
|
+
- Add transparent repair code during Manifest sync to redownload the raw data in case it was lost during an upgrade.
|
|
112
|
+
- Added OCI manifest as an allowed media type in the Docker manifest list schema.
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
62
116
|
## 2.27.9 (2026-05-14) {: #2.27.9 }
|
|
63
117
|
|
|
64
118
|
#### Bugfixes {: #2.27.9-bugfix }
|
|
@@ -163,7 +217,22 @@ No significant changes.
|
|
|
163
217
|
|
|
164
218
|
#### Misc {: #2.27.0-misc }
|
|
165
219
|
|
|
166
|
-
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
## 2.26.16 (2026-06-08) {: #2.26.16 }
|
|
224
|
+
|
|
225
|
+
#### Bugfixes {: #2.26.16-bugfix }
|
|
226
|
+
|
|
227
|
+
- Added OCI manifest as an allowed media type in the Docker manifest list schema.
|
|
228
|
+
|
|
229
|
+
---
|
|
230
|
+
|
|
231
|
+
## 2.26.15 (2026-06-02) {: #2.26.15 }
|
|
232
|
+
|
|
233
|
+
#### Bugfixes {: #2.26.15-bugfix }
|
|
234
|
+
|
|
235
|
+
- Readded backwards compatibility for manifests that haven't been migrated to new data field. Sync will try to update them to the new format and repair manifests that are missing their artifact, but it is recommended that you run the `pulpcore-manager container-handle-image-data` command to fix all manifests at once. The command has been updated to report broken manifests by repository. Broken manifests in pushed repositories need to be deleted and re-pushed.
|
|
167
236
|
|
|
168
237
|
---
|
|
169
238
|
|
|
@@ -292,6 +361,8 @@ No significant changes.
|
|
|
292
361
|
|
|
293
362
|
## 2.26.0 (2025-08-14) {: #2.26.0 }
|
|
294
363
|
|
|
364
|
+
**WARNING:** If your installation pre-dates pulp_container 2.20, make sure that you run `pulpcore-manager container-handle-image-data` before upgrading to (or past) this release. If your installation began after pulp_container 2.20, or if you have already run this command at some point, this is not necessary.
|
|
365
|
+
|
|
295
366
|
#### Features {: #2.26.0-feature }
|
|
296
367
|
|
|
297
368
|
- Bump pulpcore upperbound to <3.100. pulp_container is now a Python >=3.11 project.
|
|
@@ -329,6 +400,8 @@ No significant changes.
|
|
|
329
400
|
|
|
330
401
|
## 2.25.0 (2025-04-15) {: #2.25.0 }
|
|
331
402
|
|
|
403
|
+
**WARNING:** If your installation pre-dates pulp_container 2.20, make sure that you run `pulpcore-manager container-handle-image-data` before upgrading to (or past) this release. If your installation began after pulp_container 2.20, or if you have already run this command at some point, this is not necessary.
|
|
404
|
+
|
|
332
405
|
#### Features {: #2.25.0-feature }
|
|
333
406
|
|
|
334
407
|
- Added full support for domains.
|
|
@@ -353,6 +426,14 @@ No significant changes.
|
|
|
353
426
|
|
|
354
427
|
---
|
|
355
428
|
|
|
429
|
+
## 2.24.12 (2026-07-21) {: #2.24.12 }
|
|
430
|
+
|
|
431
|
+
#### Bugfixes {: #2.24.12-bugfix }
|
|
432
|
+
|
|
433
|
+
- Added OCI manifest as an allowed media type in the Docker manifest list schema.
|
|
434
|
+
|
|
435
|
+
---
|
|
436
|
+
|
|
356
437
|
## 2.24.11 (2026-04-29) {: #2.24.11 }
|
|
357
438
|
|
|
358
439
|
#### Bugfixes {: #2.24.11-bugfix }
|
|
@@ -483,6 +564,23 @@ No significant changes.
|
|
|
483
564
|
|
|
484
565
|
---
|
|
485
566
|
|
|
567
|
+
## 2.22.10 (2026-07-23) {: #2.22.10 }
|
|
568
|
+
|
|
569
|
+
#### Bugfixes {: #2.22.10-bugfix }
|
|
570
|
+
|
|
571
|
+
- Fixed OS and architecture filters being silently ignored when filtering manifest lists in the flatpak index.
|
|
572
|
+
- Fixed a serialization issue with the FlatpakIndex cache.
|
|
573
|
+
|
|
574
|
+
---
|
|
575
|
+
|
|
576
|
+
## 2.22.9 (2026-07-21) {: #2.22.9 }
|
|
577
|
+
|
|
578
|
+
#### Bugfixes {: #2.22.9-bugfix }
|
|
579
|
+
|
|
580
|
+
- Added OCI manifest as an allowed media type in the Docker manifest list schema.
|
|
581
|
+
|
|
582
|
+
---
|
|
583
|
+
|
|
486
584
|
## 2.22.8 (2026-04-24) {: #2.22.8 }
|
|
487
585
|
|
|
488
586
|
No significant changes.
|
|
@@ -659,6 +757,23 @@ No significant changes.
|
|
|
659
757
|
|
|
660
758
|
---
|
|
661
759
|
|
|
760
|
+
## 2.20.11 (2026-07-27) {: #2.20.11 }
|
|
761
|
+
|
|
762
|
+
#### Bugfixes {: #2.20.11-bugfix }
|
|
763
|
+
|
|
764
|
+
- Fixed OS and architecture filters being silently ignored when filtering manifest lists in the flatpak index.
|
|
765
|
+
- Fixed a serialization issue with the FlatpakIndex cache.
|
|
766
|
+
|
|
767
|
+
---
|
|
768
|
+
|
|
769
|
+
## 2.20.10 (2026-07-21) {: #2.20.10 }
|
|
770
|
+
|
|
771
|
+
#### Bugfixes {: #2.20.10-bugfix }
|
|
772
|
+
|
|
773
|
+
- Added OCI manifest as an allowed media type in the Docker manifest list schema.
|
|
774
|
+
|
|
775
|
+
---
|
|
776
|
+
|
|
662
777
|
## 2.20.9 (2026-04-24) {: #2.20.9 }
|
|
663
778
|
|
|
664
779
|
No significant changes.
|
|
@@ -749,6 +864,8 @@ No significant changes.
|
|
|
749
864
|
|
|
750
865
|
## 2.20.0 (2024-05-06) {: #2.20.0 }
|
|
751
866
|
|
|
867
|
+
**NOTICE:** If you are upgrading from a previous version of pulp_container, make sure that you run `pulpcore-manager container-handle-image-data` at some point before or shortly after upgrading. This is required in order to complete the transition away from storing Manifest data as artifacts. This must be done to avoid the potential for issues with later releases of pulp_container.
|
|
868
|
+
|
|
752
869
|
### Features
|
|
753
870
|
|
|
754
871
|
- Updated the Manifest model to no longer rely on artifacts, storing all manifest data internally
|
|
@@ -777,7 +894,22 @@ No significant changes.
|
|
|
777
894
|
|
|
778
895
|
### Misc
|
|
779
896
|
|
|
780
|
-
-
|
|
897
|
+
-
|
|
898
|
+
|
|
899
|
+
---
|
|
900
|
+
|
|
901
|
+
## 2.19.13 (2026-07-27) {: #2.19.13 }
|
|
902
|
+
|
|
903
|
+
#### Bugfixes {: #2.19.13-bugfix }
|
|
904
|
+
|
|
905
|
+
- Fixed OS and architecture filters being silently ignored when filtering manifest lists in the flatpak index.
|
|
906
|
+
- Fixed a serialization issue with the FlatpakIndex cache.
|
|
907
|
+
|
|
908
|
+
---
|
|
909
|
+
|
|
910
|
+
## 2.19.12 (2026-06-08) {: #2.19.12 }
|
|
911
|
+
|
|
912
|
+
No significant changes.
|
|
781
913
|
|
|
782
914
|
---
|
|
783
915
|
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
include LICENSE
|
|
2
1
|
include pulp_container/app/webserver_snippets/*
|
|
3
|
-
include
|
|
2
|
+
include pulp_container/tests/unit/fixtures/*
|
|
3
|
+
include LICENSE
|
|
4
4
|
include CHANGES.md
|
|
5
5
|
include COMMITMENT
|
|
6
6
|
include COPYRIGHT
|
|
7
|
+
include pyproject.toml
|
|
7
8
|
include functest_requirements.txt
|
|
8
9
|
include test_requirements.txt
|
|
9
10
|
include unittest_requirements.txt
|
|
10
11
|
exclude CONTRIBUTING.md
|
|
11
12
|
exclude releasing.md
|
|
13
|
+
exclude Makefile
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pulp-container
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.29.0
|
|
4
4
|
Summary: Container plugin for the Pulp Project
|
|
5
5
|
Author-email: Pulp Team <pulp-list@redhat.com>
|
|
6
6
|
Project-URL: Homepage, https://pulpproject.org
|
|
@@ -18,7 +18,7 @@ Requires-Python: >=3.11
|
|
|
18
18
|
Description-Content-Type: text/markdown
|
|
19
19
|
License-File: LICENSE
|
|
20
20
|
Requires-Dist: jsonschema<4.27,>=4.4
|
|
21
|
-
Requires-Dist: pulpcore<3.
|
|
21
|
+
Requires-Dist: pulpcore<3.130,>=3.111.0
|
|
22
22
|
Requires-Dist: pyjwt[crypto]<2.14,>=2.4
|
|
23
23
|
Requires-Dist: pysequoia<0.2.0,>=0.1.33
|
|
24
24
|
Dynamic: license-file
|
|
@@ -24,7 +24,7 @@ from pulp_container.app.models import (
|
|
|
24
24
|
ContainerPullThroughDistribution,
|
|
25
25
|
)
|
|
26
26
|
|
|
27
|
-
TOKEN_EXPIRATION_TIME = settings
|
|
27
|
+
TOKEN_EXPIRATION_TIME = getattr(settings, "TOKEN_EXPIRATION_TIME", 300)
|
|
28
28
|
|
|
29
29
|
FakeView = namedtuple("FakeView", "action, get_object, get_serializer")
|
|
30
30
|
|
|
@@ -295,7 +295,6 @@ class PermissionChecker:
|
|
|
295
295
|
if not domain:
|
|
296
296
|
return False
|
|
297
297
|
|
|
298
|
-
print("Checking push permissions for path ", path, "and domain ", domain.name)
|
|
299
298
|
try:
|
|
300
299
|
distribution = ContainerDistribution.objects.get(base_path=path, pulp_domain=domain)
|
|
301
300
|
except ContainerDistribution.DoesNotExist:
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
from rest_framework.exceptions import APIException, NotFound, ParseError
|
|
2
2
|
|
|
3
|
+
from pulpcore.plugin.exceptions import PulpException
|
|
4
|
+
|
|
3
5
|
|
|
4
6
|
class BadGateway(APIException):
|
|
5
7
|
status_code = 502
|
|
@@ -90,6 +92,24 @@ class BlobInvalid(ParseError):
|
|
|
90
92
|
)
|
|
91
93
|
|
|
92
94
|
|
|
95
|
+
class BlobUploadUnknown(NotFound):
|
|
96
|
+
"""Exception to render a 404 with the code 'BLOB_UPLOAD_UNKNOWN'"""
|
|
97
|
+
|
|
98
|
+
def __init__(self, uuid):
|
|
99
|
+
"""Initialize the exception with the upload uuid."""
|
|
100
|
+
super().__init__(
|
|
101
|
+
detail={
|
|
102
|
+
"errors": [
|
|
103
|
+
{
|
|
104
|
+
"code": "BLOB_UPLOAD_UNKNOWN",
|
|
105
|
+
"message": "blob upload unknown to registry",
|
|
106
|
+
"detail": {"uuid": uuid},
|
|
107
|
+
}
|
|
108
|
+
]
|
|
109
|
+
}
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
|
|
93
113
|
class ManifestNotFound(NotFound):
|
|
94
114
|
"""Exception to render a 404 with the code 'MANIFEST_UNKNOWN'"""
|
|
95
115
|
|
|
@@ -144,6 +164,19 @@ class ManifestSignatureInvalid(ParseError):
|
|
|
144
164
|
)
|
|
145
165
|
|
|
146
166
|
|
|
167
|
+
class ContainerBuildError(PulpException):
|
|
168
|
+
"""Exception to signal that building or pushing an OCI image failed."""
|
|
169
|
+
|
|
170
|
+
error_code = "CON0001"
|
|
171
|
+
|
|
172
|
+
def __init__(self, message):
|
|
173
|
+
"""Initialize the exception with the decoded stderr of the failed podman command."""
|
|
174
|
+
self.message = message
|
|
175
|
+
|
|
176
|
+
def __str__(self):
|
|
177
|
+
return self.message
|
|
178
|
+
|
|
179
|
+
|
|
147
180
|
class InvalidRequest(ParseError):
|
|
148
181
|
"""An exception to render an HTTP 400 response."""
|
|
149
182
|
|
{pulp_container-2.28.0 → pulp_container-2.29.0}/pulp_container/app/global_access_conditions.py
RENAMED
|
@@ -28,9 +28,10 @@ def has_namespace_obj_perms(request, view, action, permission):
|
|
|
28
28
|
if type(obj) is models.ContainerDistribution:
|
|
29
29
|
namespace = obj.namespace
|
|
30
30
|
return request.user.has_perm(permission, namespace)
|
|
31
|
-
elif type(obj) is models.ContainerPushRepository:
|
|
31
|
+
elif type(obj) is models.ContainerPushRepository or type(obj) is models.ContainerRepository:
|
|
32
32
|
for dist in obj.distributions.all():
|
|
33
|
-
|
|
33
|
+
namespace = dist.cast().namespace
|
|
34
|
+
if namespace and request.user.has_perm(permission, namespace):
|
|
34
35
|
return True
|
|
35
36
|
elif type(obj) is models.ContainerPullThroughDistribution:
|
|
36
37
|
namespace = obj.namespace
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Generated by Django 5.2.13 on 2026-06-03 19:16
|
|
2
|
+
|
|
3
|
+
from django.db import migrations
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Migration(migrations.Migration):
|
|
7
|
+
|
|
8
|
+
dependencies = [
|
|
9
|
+
('container', '0049_manifestsignature_fingerprint'),
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
operations = [
|
|
13
|
+
migrations.AlterModelOptions(
|
|
14
|
+
name='containernamespace',
|
|
15
|
+
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')]},
|
|
16
|
+
),
|
|
17
|
+
]
|
|
@@ -2,7 +2,6 @@ import json
|
|
|
2
2
|
import os
|
|
3
3
|
import re
|
|
4
4
|
import tempfile
|
|
5
|
-
import time
|
|
6
5
|
from gettext import gettext as _
|
|
7
6
|
from logging import getLogger
|
|
8
7
|
|
|
@@ -458,6 +457,7 @@ class ContainerNamespace(BaseModel, AutoAddObjPermsMixin):
|
|
|
458
457
|
("namespace_push_containerdistribution", "Push to any distribution in a namespace"),
|
|
459
458
|
("namespace_change_containerdistribution", "Change any distribution in a namespace"),
|
|
460
459
|
("namespace_view_containerpushrepository", "View any push repository in a namespace"),
|
|
460
|
+
("namespace_view_containerrepository", "View any repository in a namespace"),
|
|
461
461
|
(
|
|
462
462
|
"namespace_modify_content_containerpushrepository",
|
|
463
463
|
"Modify content in any push repository in a namespace",
|
|
@@ -470,6 +470,7 @@ class ContainerNamespace(BaseModel, AutoAddObjPermsMixin):
|
|
|
470
470
|
"namespace_change_containerpushrepository",
|
|
471
471
|
"Update any existing push repository in a namespace",
|
|
472
472
|
),
|
|
473
|
+
("namespace_change_containerrepository", "Change any repository in a namespace"),
|
|
473
474
|
(
|
|
474
475
|
"manage_roles_containernamespace",
|
|
475
476
|
"Can manage role assignments on container namespace",
|
|
@@ -947,8 +948,7 @@ INCOMPLETE_EXT = ".part"
|
|
|
947
948
|
|
|
948
949
|
def generate_filename(instance, filename):
|
|
949
950
|
"""Method for generating upload file name"""
|
|
950
|
-
|
|
951
|
-
return time.strftime(filename)
|
|
951
|
+
return os.path.join(instance.upload_dir, str(instance.pk) + INCOMPLETE_EXT)
|
|
952
952
|
|
|
953
953
|
|
|
954
954
|
class Upload(CoreUpload):
|
|
@@ -45,7 +45,13 @@ from rest_framework.viewsets import ViewSet
|
|
|
45
45
|
from pulpcore.plugin import pulp_hashlib
|
|
46
46
|
from pulpcore.plugin.exceptions import TimeoutException
|
|
47
47
|
from pulpcore.plugin.files import PulpTemporaryUploadedFile
|
|
48
|
-
from pulpcore.plugin.models import
|
|
48
|
+
from pulpcore.plugin.models import (
|
|
49
|
+
Artifact,
|
|
50
|
+
ContentArtifact,
|
|
51
|
+
RemoteArtifact,
|
|
52
|
+
Repository,
|
|
53
|
+
UploadChunk,
|
|
54
|
+
)
|
|
49
55
|
from pulpcore.plugin.tasking import dispatch
|
|
50
56
|
from pulpcore.plugin.util import get_domain, get_objects_for_user, get_url
|
|
51
57
|
|
|
@@ -60,6 +66,7 @@ from pulp_container.app.exceptions import (
|
|
|
60
66
|
BadGateway,
|
|
61
67
|
BlobInvalid,
|
|
62
68
|
BlobNotFound,
|
|
69
|
+
BlobUploadUnknown,
|
|
63
70
|
GatewayTimeout,
|
|
64
71
|
InvalidRequest,
|
|
65
72
|
ManifestInvalid,
|
|
@@ -73,7 +80,7 @@ from pulp_container.app.redirects import (
|
|
|
73
80
|
FileStorageRedirects,
|
|
74
81
|
S3StorageRedirects,
|
|
75
82
|
)
|
|
76
|
-
from pulp_container.app.tasks import aadd_and_remove, download_image_data
|
|
83
|
+
from pulp_container.app.tasks import aadd_and_remove, download_image_data, recursive_remove_content
|
|
77
84
|
from pulp_container.app.token_verification import (
|
|
78
85
|
RegistryAuthentication,
|
|
79
86
|
RegistryPermission,
|
|
@@ -88,6 +95,7 @@ from pulp_container.app.utils import (
|
|
|
88
95
|
get_accepted_media_types,
|
|
89
96
|
get_full_path,
|
|
90
97
|
has_task_completed,
|
|
98
|
+
is_media_type_accepted,
|
|
91
99
|
validate_manifest,
|
|
92
100
|
)
|
|
93
101
|
from pulp_container.constants import (
|
|
@@ -159,11 +167,11 @@ class ManifestResponse(Response):
|
|
|
159
167
|
manifest_media_type = manifest.media_type
|
|
160
168
|
if request:
|
|
161
169
|
accepted_media_types = get_accepted_media_types(request.headers)
|
|
162
|
-
if (
|
|
163
|
-
manifest_media_type
|
|
164
|
-
and manifest_media_type != MEDIA_TYPE.MANIFEST_V1
|
|
170
|
+
if accepted_media_types and not is_media_type_accepted(
|
|
171
|
+
accepted_media_types, manifest_media_type
|
|
165
172
|
):
|
|
166
|
-
|
|
173
|
+
if manifest_media_type != MEDIA_TYPE.MANIFEST_V1:
|
|
174
|
+
raise ManifestNotFound(reference=tag.name)
|
|
167
175
|
|
|
168
176
|
# Schema v1 manifests are always returned with the signed content type
|
|
169
177
|
if manifest_media_type == MEDIA_TYPE.MANIFEST_V1:
|
|
@@ -279,7 +287,7 @@ class ContainerRegistryApiMixin:
|
|
|
279
287
|
This allows deployments to use custom authentication backends (e.g. remote
|
|
280
288
|
header-based auth) alongside standard Basic auth for container registry operations.
|
|
281
289
|
"""
|
|
282
|
-
if settings
|
|
290
|
+
if getattr(settings, "TOKEN_AUTH_DISABLED", False):
|
|
283
291
|
return [RegistryAuthentication, *api_settings.DEFAULT_AUTHENTICATION_CLASSES]
|
|
284
292
|
return [TokenAuthentication]
|
|
285
293
|
|
|
@@ -288,7 +296,7 @@ class ContainerRegistryApiMixin:
|
|
|
288
296
|
"""
|
|
289
297
|
List of permission classes to check for this view.
|
|
290
298
|
"""
|
|
291
|
-
if settings
|
|
299
|
+
if getattr(settings, "TOKEN_AUTH_DISABLED", False):
|
|
292
300
|
return [RegistryPermission]
|
|
293
301
|
return [TokenPermission]
|
|
294
302
|
|
|
@@ -436,11 +444,9 @@ class ContainerRegistryApiMixin:
|
|
|
436
444
|
repository = distribution.repository
|
|
437
445
|
if repository:
|
|
438
446
|
repository = repository.cast()
|
|
439
|
-
if not repository.PUSH_ENABLED:
|
|
440
|
-
raise RepositoryInvalid(name=path, message="Repository is read-only.")
|
|
441
447
|
elif create:
|
|
442
448
|
with transaction.atomic():
|
|
443
|
-
repository = serializers.
|
|
449
|
+
repository = serializers.ContainerRepositorySerializer.get_or_create(
|
|
444
450
|
{"name": path, "pulp_domain": domain}
|
|
445
451
|
)
|
|
446
452
|
distribution.repository = repository
|
|
@@ -451,11 +457,22 @@ class ContainerRegistryApiMixin:
|
|
|
451
457
|
|
|
452
458
|
def create_dr(self, path, request):
|
|
453
459
|
domain = get_domain()
|
|
460
|
+
repository_types = [
|
|
461
|
+
models.ContainerRepository.get_pulp_type(),
|
|
462
|
+
models.ContainerPushRepository.get_pulp_type(),
|
|
463
|
+
]
|
|
454
464
|
with transaction.atomic():
|
|
455
465
|
try:
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
466
|
+
# Handle new default of ContainerRepository and fallback old ContainerPushRepository
|
|
467
|
+
repository = Repository.objects.filter(name=path, pulp_domain=domain).first()
|
|
468
|
+
if repository:
|
|
469
|
+
if repository.pulp_type not in repository_types:
|
|
470
|
+
raise RepositoryInvalid(name=path, message="Repository is read-only.")
|
|
471
|
+
repository = repository.cast()
|
|
472
|
+
else:
|
|
473
|
+
repository = serializers.ContainerRepositorySerializer.get_or_create(
|
|
474
|
+
{"name": path, "pulp_domain": domain}
|
|
475
|
+
)
|
|
459
476
|
distribution = serializers.ContainerDistributionSerializer.get_or_create(
|
|
460
477
|
{"base_path": path, "name": path, "pulp_domain": domain},
|
|
461
478
|
{"repository": get_url(repository)},
|
|
@@ -464,9 +481,10 @@ class ContainerRegistryApiMixin:
|
|
|
464
481
|
raise RepositoryInvalid(name=path, message="Repository is read-only.")
|
|
465
482
|
|
|
466
483
|
if distribution.repository:
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
484
|
+
if repository.pk != distribution.repository.pk:
|
|
485
|
+
raise RepositoryInvalid(
|
|
486
|
+
name=path, message="Repository is not available for push."
|
|
487
|
+
)
|
|
470
488
|
else:
|
|
471
489
|
distribution.repository = repository
|
|
472
490
|
distribution.save()
|
|
@@ -517,7 +535,7 @@ class VersionView(ContainerRegistryApiMixin, APIView):
|
|
|
517
535
|
"""
|
|
518
536
|
List of permission classes to check for this view.
|
|
519
537
|
"""
|
|
520
|
-
if settings
|
|
538
|
+
if getattr(settings, "TOKEN_AUTH_DISABLED", False):
|
|
521
539
|
return [IsAuthenticated]
|
|
522
540
|
return [TokenPermission]
|
|
523
541
|
|
|
@@ -609,7 +627,7 @@ class CatalogView(ContainerRegistryApiMixin, ListAPIView):
|
|
|
609
627
|
distribution_permission = "container.pull_containerdistribution"
|
|
610
628
|
namespace_permission = "container.namespace_pull_containerdistribution"
|
|
611
629
|
|
|
612
|
-
if settings
|
|
630
|
+
if getattr(settings, "TOKEN_AUTH_DISABLED", False):
|
|
613
631
|
return queryset
|
|
614
632
|
|
|
615
633
|
public_repositories = queryset.filter(private=False)
|
|
@@ -1014,6 +1032,30 @@ class BlobUploads(ContainerRegistryApiMixin, ViewSet):
|
|
|
1014
1032
|
|
|
1015
1033
|
return UploadResponse(upload=upload, path=path, request=request)
|
|
1016
1034
|
|
|
1035
|
+
def get(self, request, path, pk=None):
|
|
1036
|
+
"""
|
|
1037
|
+
Retrieve the status of an upload.
|
|
1038
|
+
"""
|
|
1039
|
+
_, repository = self.get_dr_push(request, path)
|
|
1040
|
+
upload = get_object_or_404(models.Upload, repository=repository, pk=pk)
|
|
1041
|
+
return UploadResponse(upload=upload, path=path, request=request, status=204)
|
|
1042
|
+
|
|
1043
|
+
def head(self, request, path, pk=None):
|
|
1044
|
+
"""Respond to HEAD requests about blob uploads."""
|
|
1045
|
+
return self.get(request, path, pk=pk)
|
|
1046
|
+
|
|
1047
|
+
def destroy(self, request, path, pk=None):
|
|
1048
|
+
"""
|
|
1049
|
+
Cancel an outstanding blob upload.
|
|
1050
|
+
"""
|
|
1051
|
+
_, repository = self.get_dr_push(request, path)
|
|
1052
|
+
try:
|
|
1053
|
+
upload = models.Upload.objects.get(repository=repository, pk=pk)
|
|
1054
|
+
except models.Upload.DoesNotExist:
|
|
1055
|
+
raise BlobUploadUnknown(uuid=pk)
|
|
1056
|
+
upload.delete()
|
|
1057
|
+
return Response(status=204)
|
|
1058
|
+
|
|
1017
1059
|
def put(self, request, path, pk=None):
|
|
1018
1060
|
"""
|
|
1019
1061
|
Create a blob from uploaded chunks.
|
|
@@ -1185,6 +1227,34 @@ class Blobs(RedirectsMixin, ContainerRegistryApiMixin, ViewSet):
|
|
|
1185
1227
|
raise BlobNotFound(digest=pk)
|
|
1186
1228
|
return blob_url
|
|
1187
1229
|
|
|
1230
|
+
def destroy(self, request, path, pk=None):
|
|
1231
|
+
"""
|
|
1232
|
+
Delete a blob identified by digest.
|
|
1233
|
+
"""
|
|
1234
|
+
if not pk.startswith("sha256:"):
|
|
1235
|
+
raise InvalidRequest(message="A blob can only be deleted by digest.")
|
|
1236
|
+
|
|
1237
|
+
_, repository = self.get_dr_push(request, path)
|
|
1238
|
+
latest_version = repository.latest_version()
|
|
1239
|
+
|
|
1240
|
+
if blob := models.Blob.objects.filter(digest=pk, pk__in=latest_version.content).first():
|
|
1241
|
+
dispatch(
|
|
1242
|
+
aadd_and_remove,
|
|
1243
|
+
exclusive_resources=[repository],
|
|
1244
|
+
kwargs={
|
|
1245
|
+
"repository_pk": str(repository.pk),
|
|
1246
|
+
"add_content_units": [],
|
|
1247
|
+
"remove_content_units": [str(blob.pk)],
|
|
1248
|
+
},
|
|
1249
|
+
immediate=True,
|
|
1250
|
+
deferred=True,
|
|
1251
|
+
)
|
|
1252
|
+
elif pending_blob := repository.pending_blobs.filter(digest=pk).first():
|
|
1253
|
+
repository.pending_blobs.remove(pending_blob)
|
|
1254
|
+
else:
|
|
1255
|
+
raise BlobNotFound(digest=pk)
|
|
1256
|
+
return Response(status=202)
|
|
1257
|
+
|
|
1188
1258
|
|
|
1189
1259
|
class Manifests(RedirectsMixin, ContainerRegistryApiMixin, ViewSet):
|
|
1190
1260
|
"""
|
|
@@ -1329,6 +1399,36 @@ class Manifests(RedirectsMixin, ContainerRegistryApiMixin, ViewSet):
|
|
|
1329
1399
|
# Fallthrough catchall, no manifest or tag found
|
|
1330
1400
|
raise ManifestNotFound(reference=pk)
|
|
1331
1401
|
|
|
1402
|
+
def destroy(self, request, path, pk=None):
|
|
1403
|
+
"""
|
|
1404
|
+
Delete a manifest identified by digest.
|
|
1405
|
+
"""
|
|
1406
|
+
if not pk.startswith("sha256:"):
|
|
1407
|
+
raise InvalidRequest(message="A manifest can only be deleted by digest.")
|
|
1408
|
+
|
|
1409
|
+
_, repository = self.get_dr_push(request, path)
|
|
1410
|
+
latest_version = repository.latest_version()
|
|
1411
|
+
|
|
1412
|
+
manifest = models.Manifest.objects.filter(digest=pk, pk__in=latest_version.content).first()
|
|
1413
|
+
if not manifest:
|
|
1414
|
+
manifest = repository.pending_manifests.filter(digest=pk).first()
|
|
1415
|
+
if not manifest:
|
|
1416
|
+
raise ManifestNotFound(reference=pk)
|
|
1417
|
+
repository.pending_manifests.remove(manifest)
|
|
1418
|
+
|
|
1419
|
+
tags = models.Tag.objects.filter(tagged_manifest=manifest, pk__in=latest_version.content)
|
|
1420
|
+
content_units = [str(manifest.pk)] + [str(tag.pk) for tag in tags]
|
|
1421
|
+
|
|
1422
|
+
dispatch(
|
|
1423
|
+
recursive_remove_content,
|
|
1424
|
+
exclusive_resources=[repository],
|
|
1425
|
+
kwargs={
|
|
1426
|
+
"repository_pk": str(repository.pk),
|
|
1427
|
+
"content_units": content_units,
|
|
1428
|
+
},
|
|
1429
|
+
)
|
|
1430
|
+
return Response(status=202)
|
|
1431
|
+
|
|
1332
1432
|
def get_content_units_to_add(self, manifest, tag=None):
|
|
1333
1433
|
add_content_units = [str(manifest.pk)]
|
|
1334
1434
|
if tag:
|