pulp-container 2.28.0__tar.gz → 2.28.1__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.
Files changed (149) hide show
  1. {pulp_container-2.28.0 → pulp_container-2.28.1}/CHANGES.md +9 -0
  2. {pulp_container-2.28.0 → pulp_container-2.28.1}/MANIFEST.in +1 -0
  3. {pulp_container-2.28.0 → pulp_container-2.28.1}/PKG-INFO +2 -2
  4. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/__init__.py +1 -1
  5. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/authorization.py +1 -1
  6. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/json_schemas.py +1 -0
  7. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/registry_api.py +4 -4
  8. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/tasks/sync_stages.py +35 -10
  9. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/tests/functional/api/test_content_cache.py +1 -1
  10. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/tests/functional/api/test_domains.py +4 -1
  11. pulp_container-2.28.1/pulp_container/tests/unit/fixtures/ryuk_0.13.0_manifest_list.json +154 -0
  12. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/tests/unit/test_json_schemas.py +29 -0
  13. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container.egg-info/PKG-INFO +2 -2
  14. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container.egg-info/SOURCES.txt +2 -1
  15. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container.egg-info/requires.txt +1 -1
  16. {pulp_container-2.28.0 → pulp_container-2.28.1}/pyproject.toml +4 -4
  17. {pulp_container-2.28.0 → pulp_container-2.28.1}/COMMITMENT +0 -0
  18. {pulp_container-2.28.0 → pulp_container-2.28.1}/COPYRIGHT +0 -0
  19. {pulp_container-2.28.0 → pulp_container-2.28.1}/LICENSE +0 -0
  20. {pulp_container-2.28.0 → pulp_container-2.28.1}/README.rst +0 -0
  21. {pulp_container-2.28.0 → pulp_container-2.28.1}/functest_requirements.txt +0 -0
  22. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/__init__.py +0 -0
  23. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/access_policy.py +0 -0
  24. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/cache.py +0 -0
  25. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/checks.py +0 -0
  26. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/content.py +0 -0
  27. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/downloaders.py +0 -0
  28. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/dynaconf_hooks.py +0 -0
  29. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/exceptions.py +0 -0
  30. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/fields.py +0 -0
  31. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/global_access_conditions.py +0 -0
  32. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/management/__init__.py +0 -0
  33. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/management/commands/__init__.py +0 -0
  34. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/management/commands/container-handle-image-data.py +0 -0
  35. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/management/commands/container-repair-media-type.py +0 -0
  36. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/migrations/0001_initial.py +0 -0
  37. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/migrations/0001_squashed_0032_upload_artifact.py +0 -0
  38. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/migrations/0002_containerrepository.py +0 -0
  39. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/migrations/0003_oci_mediatype.py +0 -0
  40. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/migrations/0004_upload.py +0 -0
  41. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/migrations/0005_contentredirectcontentguard.py +0 -0
  42. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/migrations/0006_containerpushrepository.py +0 -0
  43. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/migrations/0007_clear_tags_artifacts_refs.py +0 -0
  44. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/migrations/0008_include_exclude_tags.py +0 -0
  45. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/migrations/0009_container_namespace.py +0 -0
  46. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/migrations/0010_remove_uploadchunk.py +0 -0
  47. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/migrations/0011_add_container_repository_permissions.py +0 -0
  48. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/migrations/0012_add_container_namespace_permissions.py +0 -0
  49. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/migrations/0013_add_pull_push_permissions.py +0 -0
  50. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/migrations/0014_containerdistribution_private.py +0 -0
  51. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/migrations/0015_manage_tags_push_repo.py +0 -0
  52. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/migrations/0016_add_delete_versions_permission.py +0 -0
  53. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/migrations/0017_add_granular_perms.py +0 -0
  54. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/migrations/0018_containerdistribution_description.py +0 -0
  55. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/migrations/0019_DATA_distribution_model_swap.py +0 -0
  56. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/migrations/0020_update_push_repo_perms.py +0 -0
  57. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/migrations/0021_data_move_redirect_content_guard_to_core.py +0 -0
  58. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/migrations/0022_delete_contentredirectcontentguard.py +0 -0
  59. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/migrations/0023_manifestsignature.py +0 -0
  60. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/migrations/0024_containerremote_sigstore.py +0 -0
  61. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/migrations/0025_signature_stored_in_textfield.py +0 -0
  62. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/migrations/0026_manifest_signing_service.py +0 -0
  63. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/migrations/0027_data_translate_perms_to_roles.py +0 -0
  64. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/migrations/0028_add_role_manage_permissions.py +0 -0
  65. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/migrations/0029_remove_blob_media_type.py +0 -0
  66. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/migrations/0030_enforce_tagged_manifest_reference.py +0 -0
  67. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/migrations/0031_replace_charf_with_textf.py +0 -0
  68. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/migrations/0032_upload_artifact.py +0 -0
  69. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/migrations/0033_raise_warning_for_repair.py +0 -0
  70. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/migrations/0034_translate_signed_schema.py +0 -0
  71. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/migrations/0035_alter_blob_content_ptr_and_more.py +0 -0
  72. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/migrations/0036_containerpushrepository_pending_blobs_manifests.py +0 -0
  73. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/migrations/0037_create_pull_through_cache_models.py +0 -0
  74. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/migrations/0038_add_manifest_metadata_fields.py +0 -0
  75. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/migrations/0039_manifest_data.py +0 -0
  76. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/migrations/0040_add_remote_repo_filter.py +0 -0
  77. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/migrations/0041_add_pull_through_pull_permissions.py +0 -0
  78. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/migrations/0042_add_manifest_nature_field.py +0 -0
  79. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/migrations/0043_add_os_arch_image_size_manifest_fields.py +0 -0
  80. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/migrations/0044_add_domain.py +0 -0
  81. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/migrations/0045_alter_manifest_compressed_image_size.py +0 -0
  82. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/migrations/0046_alter_manifest_listed_manifests.py +0 -0
  83. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/migrations/0047_containernamespace_pulp_labels.py +0 -0
  84. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/migrations/0048_containerremote_includes_excludes.py +0 -0
  85. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/migrations/0049_manifestsignature_fingerprint.py +0 -0
  86. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/migrations/__init__.py +0 -0
  87. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/modelresource.py +0 -0
  88. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/models.py +0 -0
  89. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/redirects.py +0 -0
  90. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/registry.py +0 -0
  91. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/replica.py +0 -0
  92. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/serializers.py +0 -0
  93. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/settings.py +0 -0
  94. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/tasks/__init__.py +0 -0
  95. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/tasks/builder.py +0 -0
  96. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/tasks/download_image_data.py +0 -0
  97. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/tasks/recursive_add.py +0 -0
  98. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/tasks/recursive_remove.py +0 -0
  99. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/tasks/sign.py +0 -0
  100. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/tasks/synchronize.py +0 -0
  101. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/tasks/tag.py +0 -0
  102. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/tasks/untag.py +0 -0
  103. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/token_verification.py +0 -0
  104. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/urls.py +0 -0
  105. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/utils.py +0 -0
  106. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/viewsets.py +0 -0
  107. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/webserver_snippets/__init__.py +0 -0
  108. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/webserver_snippets/apache.conf +0 -0
  109. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/app/webserver_snippets/nginx.conf +0 -0
  110. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/constants.py +0 -0
  111. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/tests/__init__.py +0 -0
  112. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/tests/functional/__init__.py +0 -0
  113. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/tests/functional/api/__init__.py +0 -0
  114. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/tests/functional/api/test_build_images.py +0 -0
  115. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/tests/functional/api/test_crud_distributions.py +0 -0
  116. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/tests/functional/api/test_crud_remotes.py +0 -0
  117. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/tests/functional/api/test_flatpak.py +0 -0
  118. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/tests/functional/api/test_pull_content.py +0 -0
  119. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/tests/functional/api/test_pull_through_cache.py +0 -0
  120. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/tests/functional/api/test_pulpimportexport.py +0 -0
  121. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/tests/functional/api/test_push_content.py +0 -0
  122. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/tests/functional/api/test_push_signatures.py +0 -0
  123. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/tests/functional/api/test_rbac_push_repositories.py +0 -0
  124. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/tests/functional/api/test_rbac_remotes.py +0 -0
  125. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/tests/functional/api/test_rbac_repo_content.py +0 -0
  126. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/tests/functional/api/test_rbac_repo_versions.py +0 -0
  127. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/tests/functional/api/test_rbac_sync_repositories.py +0 -0
  128. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/tests/functional/api/test_recursive_add.py +0 -0
  129. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/tests/functional/api/test_recursive_remove.py +0 -0
  130. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/tests/functional/api/test_remote_filter_pull_through.py +0 -0
  131. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/tests/functional/api/test_repositories_list.py +0 -0
  132. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/tests/functional/api/test_sign_manifests.py +0 -0
  133. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/tests/functional/api/test_sync.py +0 -0
  134. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/tests/functional/api/test_sync_signatures.py +0 -0
  135. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/tests/functional/api/test_tagging_images.py +0 -0
  136. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/tests/functional/api/test_token_authentication.py +0 -0
  137. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/tests/functional/conftest.py +0 -0
  138. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/tests/functional/constants.py +0 -0
  139. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/tests/functional/utils.py +0 -0
  140. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/tests/unit/__init__.py +0 -0
  141. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/tests/unit/test_models.py +0 -0
  142. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/tests/unit/test_serializers.py +0 -0
  143. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container/tests/unit/test_sync_stages.py +0 -0
  144. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container.egg-info/dependency_links.txt +0 -0
  145. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container.egg-info/entry_points.txt +0 -0
  146. {pulp_container-2.28.0 → pulp_container-2.28.1}/pulp_container.egg-info/top_level.txt +0 -0
  147. {pulp_container-2.28.0 → pulp_container-2.28.1}/setup.cfg +0 -0
  148. {pulp_container-2.28.0 → pulp_container-2.28.1}/test_requirements.txt +0 -0
  149. {pulp_container-2.28.0 → pulp_container-2.28.1}/unittest_requirements.txt +0 -0
@@ -8,6 +8,15 @@
8
8
 
9
9
  [//]: # (towncrier release notes start)
10
10
 
11
+ ## 2.28.1 (2026-07-22) {: #2.28.1 }
12
+
13
+ #### Bugfixes {: #2.28.1-bugfix }
14
+
15
+ - Add transparent repair code during Manifest sync to redownload the raw data in case it was lost during an upgrade.
16
+ - Added OCI manifest as an allowed media type in the Docker manifest list schema.
17
+
18
+ ---
19
+
11
20
  ## 2.28.0 (2026-05-29) {: #2.28.0 }
12
21
 
13
22
  #### Features {: #2.28.0-feature }
@@ -9,3 +9,4 @@ include test_requirements.txt
9
9
  include unittest_requirements.txt
10
10
  exclude CONTRIBUTING.md
11
11
  exclude releasing.md
12
+ include pulp_container/tests/unit/fixtures/*
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pulp-container
3
- Version: 2.28.0
3
+ Version: 2.28.1
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.115,>=3.111.0
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 @@ class PulpContainerPluginAppConfig(PulpPluginAppConfig):
24
24
 
25
25
  name = "pulp_container.app"
26
26
  label = "container"
27
- version = "2.28.0"
27
+ version = "2.28.1"
28
28
  python_package_name = "pulp-container"
29
29
  domain_compatible = True
30
30
 
@@ -24,7 +24,7 @@ from pulp_container.app.models import (
24
24
  ContainerPullThroughDistribution,
25
25
  )
26
26
 
27
- TOKEN_EXPIRATION_TIME = settings.get("TOKEN_EXPIRATION_TIME", 300)
27
+ TOKEN_EXPIRATION_TIME = getattr(settings, "TOKEN_EXPIRATION_TIME", 300)
28
28
 
29
29
  FakeView = namedtuple("FakeView", "action, get_object, get_serializer")
30
30
 
@@ -124,6 +124,7 @@ DOCKER_MANIFEST_LIST_V2_SCHEMA = {
124
124
  "enum": [
125
125
  MEDIA_TYPE.MANIFEST_V2,
126
126
  MEDIA_TYPE.MANIFEST_V1,
127
+ MEDIA_TYPE.MANIFEST_OCI,
127
128
  ],
128
129
  },
129
130
  "size": {"type": "number"},
@@ -279,7 +279,7 @@ class ContainerRegistryApiMixin:
279
279
  This allows deployments to use custom authentication backends (e.g. remote
280
280
  header-based auth) alongside standard Basic auth for container registry operations.
281
281
  """
282
- if settings.get("TOKEN_AUTH_DISABLED", False):
282
+ if getattr(settings, "TOKEN_AUTH_DISABLED", False):
283
283
  return [RegistryAuthentication, *api_settings.DEFAULT_AUTHENTICATION_CLASSES]
284
284
  return [TokenAuthentication]
285
285
 
@@ -288,7 +288,7 @@ class ContainerRegistryApiMixin:
288
288
  """
289
289
  List of permission classes to check for this view.
290
290
  """
291
- if settings.get("TOKEN_AUTH_DISABLED", False):
291
+ if getattr(settings, "TOKEN_AUTH_DISABLED", False):
292
292
  return [RegistryPermission]
293
293
  return [TokenPermission]
294
294
 
@@ -517,7 +517,7 @@ class VersionView(ContainerRegistryApiMixin, APIView):
517
517
  """
518
518
  List of permission classes to check for this view.
519
519
  """
520
- if settings.get("TOKEN_AUTH_DISABLED", False):
520
+ if getattr(settings, "TOKEN_AUTH_DISABLED", False):
521
521
  return [IsAuthenticated]
522
522
  return [TokenPermission]
523
523
 
@@ -609,7 +609,7 @@ class CatalogView(ContainerRegistryApiMixin, ListAPIView):
609
609
  distribution_permission = "container.pull_containerdistribution"
610
610
  namespace_permission = "container.namespace_pull_containerdistribution"
611
611
 
612
- if settings.get("TOKEN_AUTH_DISABLED", False):
612
+ if getattr(settings, "TOKEN_AUTH_DISABLED", False):
613
613
  return queryset
614
614
 
615
615
  public_repositories = queryset.filter(private=False)
@@ -98,7 +98,15 @@ class ContainerFirstStage(Stage):
98
98
  digest=digest, pulp_domain=get_domain()
99
99
  ).afirst():
100
100
  raw_text_data = manifest.data
101
- content_data = json.loads(raw_text_data)
101
+ if raw_text_data is None:
102
+ # This situation allegedly happens on some upgrade paths.
103
+ # A migration should mark the field not Null eventually. At that point this
104
+ # workaround can be removed.
105
+ content_data, raw_text_data, _ = await self._download_manifest_data(response.url)
106
+ manifest.data = raw_text_data
107
+ await manifest.asave()
108
+ else:
109
+ content_data = json.loads(raw_text_data)
102
110
  else:
103
111
  if not original_reference.startswith("sha256:") and digest:
104
112
  # Fetch the tag with its digest
@@ -522,6 +530,8 @@ class ContainerFirstStage(Stage):
522
530
 
523
531
  """
524
532
  digest = manifest_data["digest"]
533
+ # in oci-index spec, platform is an optional field
534
+ platform = manifest_data.get("platform", None)
525
535
  relative_url = "/v2/{name}/manifests/{digest}".format(
526
536
  name=self.remote.namespaced_upstream_name, digest=digest
527
537
  )
@@ -530,15 +540,30 @@ class ContainerFirstStage(Stage):
530
540
  if manifest := await Manifest.objects.filter(
531
541
  digest=digest, pulp_domain=get_domain()
532
542
  ).afirst():
533
- content_data = json.loads(manifest.data)
534
-
535
- content_data, manifest = await self._download_and_instantiate_manifest(manifest_url, digest)
536
-
537
- # in oci-index spec, platform is an optional field
538
- platform = manifest_data.get("platform", None)
539
- if platform:
540
- manifest.os = platform["os"]
541
- manifest.architecture = platform["architecture"]
543
+ raw_text_data = manifest.data
544
+ if raw_text_data is None:
545
+ # This situation allegedly happens on some upgrade paths.
546
+ # A migration should mark the field not Null eventually. At that point this
547
+ # workaround can be removed.
548
+ content_data, raw_text_data, response = await self._download_manifest_data(
549
+ manifest_url
550
+ )
551
+ media_type = determine_media_type(content_data, response)
552
+ validate_manifest(content_data, media_type, digest)
553
+ manifest.data = raw_text_data
554
+ if platform:
555
+ manifest.os = platform["os"]
556
+ manifest.architecture = platform["architecture"]
557
+ await manifest.asave()
558
+ else:
559
+ content_data = json.loads(raw_text_data)
560
+ else:
561
+ content_data, manifest = await self._download_and_instantiate_manifest(
562
+ manifest_url, digest
563
+ )
564
+ if platform:
565
+ manifest.os = platform["os"]
566
+ manifest.architecture = platform["architecture"]
542
567
  man_dc = DeclarativeContent(content=manifest)
543
568
  return {"manifest_dc": man_dc, "platform": platform, "content_data": content_data}
544
569
 
@@ -76,7 +76,7 @@ def test_content_cache(
76
76
  monitor_task,
77
77
  ):
78
78
  """A test case that verifies the functionality of the Redis caching machinery."""
79
- if not pulp_settings.get("CACHE_ENABLED"):
79
+ if not getattr(pulp_settings, "CACHE_ENABLED", False):
80
80
  pytest.skip("The caching machinery was not enabled")
81
81
 
82
82
  repo = container_repository_factory()
@@ -366,7 +366,10 @@ def test_domain_content_replication(
366
366
  pulpcore_bindings.UpstreamPulpsApi, upstream_pulp_body, pulp_domain=replica_domain.name
367
367
  )
368
368
  # Run the replicate task and assert that all tasks successfully complete.
369
- response = pulpcore_bindings.UpstreamPulpsApi.replicate(upstream_pulp.pulp_href)
369
+ response = pulpcore_bindings.UpstreamPulpsApi.replicate(
370
+ upstream_pulp.pulp_href,
371
+ upstream_pulp_replicate=pulpcore_bindings.module.UpstreamPulpReplicate(),
372
+ )
370
373
  monitor_task_group(response.task_group)
371
374
 
372
375
  counts = {}
@@ -0,0 +1,154 @@
1
+ {
2
+ "schemaVersion": 2,
3
+ "mediaType": "application/vnd.docker.distribution.manifest.list.v2+json",
4
+ "manifests": [
5
+ {
6
+ "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
7
+ "size": 1157,
8
+ "digest": "sha256:dbf39a38239100ad20536e75f0066163bdf989c8b6a07116c8814f991878756f",
9
+ "platform": {
10
+ "architecture": "amd64",
11
+ "os": "windows",
12
+ "os.version": "10.0.17763.7678"
13
+ }
14
+ },
15
+ {
16
+ "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
17
+ "size": 1157,
18
+ "digest": "sha256:92ae77da69814eadc33ece22a9a1f564b508fd3bc0ab6c27f53ffb3b4e2f7ff0",
19
+ "platform": {
20
+ "architecture": "amd64",
21
+ "os": "windows",
22
+ "os.version": "10.0.20348.4052"
23
+ }
24
+ },
25
+ {
26
+ "mediaType": "application/vnd.oci.image.manifest.v1+json",
27
+ "size": 662,
28
+ "digest": "sha256:1c4aaca7ec29ab100a805a90718619dba7a542f7fadc6198c8f47b1c6fc058c5",
29
+ "platform": {
30
+ "architecture": "ppc64le",
31
+ "os": "linux"
32
+ }
33
+ },
34
+ {
35
+ "mediaType": "application/vnd.oci.image.manifest.v1+json",
36
+ "size": 567,
37
+ "digest": "sha256:1f965b7a234671c706b444540c86033bbe667b3d6df3453b88a16bb897328bea",
38
+ "platform": {
39
+ "architecture": "unknown",
40
+ "os": "unknown"
41
+ }
42
+ },
43
+ {
44
+ "mediaType": "application/vnd.oci.image.manifest.v1+json",
45
+ "size": 567,
46
+ "digest": "sha256:286b5e78baf03adff94af82199af6b936c701957d94dd001cae375af41519fd3",
47
+ "platform": {
48
+ "architecture": "unknown",
49
+ "os": "unknown"
50
+ }
51
+ },
52
+ {
53
+ "mediaType": "application/vnd.oci.image.manifest.v1+json",
54
+ "size": 662,
55
+ "digest": "sha256:2a5038e0424aee30b8e1ecaf3889eb18b1496baca035b5cbdfeb79faa06e867a",
56
+ "platform": {
57
+ "architecture": "arm64",
58
+ "os": "linux"
59
+ }
60
+ },
61
+ {
62
+ "mediaType": "application/vnd.oci.image.manifest.v1+json",
63
+ "size": 662,
64
+ "digest": "sha256:2ff824f3c5b87343601f88b944039949004c4b25d5c95b95b8d513d9592abfd9",
65
+ "platform": {
66
+ "architecture": "arm",
67
+ "os": "linux",
68
+ "variant": "v7"
69
+ }
70
+ },
71
+ {
72
+ "mediaType": "application/vnd.oci.image.manifest.v1+json",
73
+ "size": 662,
74
+ "digest": "sha256:31c852ef4caf457d598a67ef9a19626a99e0080186903e15f9cacac70eaeb08f",
75
+ "platform": {
76
+ "architecture": "arm",
77
+ "os": "linux",
78
+ "variant": "v6"
79
+ }
80
+ },
81
+ {
82
+ "mediaType": "application/vnd.oci.image.manifest.v1+json",
83
+ "size": 567,
84
+ "digest": "sha256:46d7dcf2110fc9e7eb1e8bc589d7507fb4db20b36a7ae401d0f7daa5457986cd",
85
+ "platform": {
86
+ "architecture": "unknown",
87
+ "os": "unknown"
88
+ }
89
+ },
90
+ {
91
+ "mediaType": "application/vnd.oci.image.manifest.v1+json",
92
+ "size": 567,
93
+ "digest": "sha256:5af5b45d5d54da802b42c1754577d9b3b91b61bb20ca301b1de08e47b5027fb1",
94
+ "platform": {
95
+ "architecture": "unknown",
96
+ "os": "unknown"
97
+ }
98
+ },
99
+ {
100
+ "mediaType": "application/vnd.oci.image.manifest.v1+json",
101
+ "size": 567,
102
+ "digest": "sha256:6312fce3d003e5b1973f64ff61d7465c0d8a3f6216123264fd8688caace685ce",
103
+ "platform": {
104
+ "architecture": "unknown",
105
+ "os": "unknown"
106
+ }
107
+ },
108
+ {
109
+ "mediaType": "application/vnd.oci.image.manifest.v1+json",
110
+ "size": 567,
111
+ "digest": "sha256:725de179c309cd78dc85aa0e315f7a2c6230efe166d8a972113ecf47feb122d7",
112
+ "platform": {
113
+ "architecture": "unknown",
114
+ "os": "unknown"
115
+ }
116
+ },
117
+ {
118
+ "mediaType": "application/vnd.oci.image.manifest.v1+json",
119
+ "size": 662,
120
+ "digest": "sha256:9f74979cb9d95b5dd3f695e567cd5cd1806a006895d80fa9002a9e68f607f495",
121
+ "platform": {
122
+ "architecture": "amd64",
123
+ "os": "linux"
124
+ }
125
+ },
126
+ {
127
+ "mediaType": "application/vnd.oci.image.manifest.v1+json",
128
+ "size": 662,
129
+ "digest": "sha256:d5fcc1e6aaa51949c7d11e8ac9cf407efb9d52dd9f871542cfaf750c9b1ccc2b",
130
+ "platform": {
131
+ "architecture": "386",
132
+ "os": "linux"
133
+ }
134
+ },
135
+ {
136
+ "mediaType": "application/vnd.oci.image.manifest.v1+json",
137
+ "size": 567,
138
+ "digest": "sha256:f5aa3faf94fb7c630ecb8bc6d4ba506cfdbd90ff8c882710b07fb953b4cf09ae",
139
+ "platform": {
140
+ "architecture": "unknown",
141
+ "os": "unknown"
142
+ }
143
+ },
144
+ {
145
+ "mediaType": "application/vnd.oci.image.manifest.v1+json",
146
+ "size": 662,
147
+ "digest": "sha256:fa81566cb9a09b2cd72a703e17160c6cf6906a22d4eeae716ce7f0f42053efdb",
148
+ "platform": {
149
+ "architecture": "s390x",
150
+ "os": "linux"
151
+ }
152
+ }
153
+ ]
154
+ }
@@ -1,4 +1,5 @@
1
1
  import json
2
+ from pathlib import Path
2
3
 
3
4
  from django.test import TestCase
4
5
  from jsonschema import Draft7Validator
@@ -197,3 +198,31 @@ class TestOCISchema(TestCase):
197
198
  validate_manifest(manifest, MEDIA_TYPE.MANIFEST_OCI, "")
198
199
  except ManifestInvalid:
199
200
  self.fail()
201
+
202
+
203
+ class TestDockerManifestListSchema(TestCase):
204
+ """A test case for validating Docker manifest list JSON schema."""
205
+
206
+ def test_ryuk_manifest_list_with_oci_entries(self):
207
+ """
208
+ Validate a real Docker manifest list that references OCI image manifests.
209
+
210
+ testcontainers/ryuk:0.13.0 on Docker Hub publishes a Docker manifest list
211
+ containing both Docker v2 and OCI image manifest entries.
212
+ """
213
+ fixture_path = Path(__file__).parent / "fixtures" / "ryuk_0.13.0_manifest_list.json"
214
+ manifest = json.loads(fixture_path.read_text())
215
+ entry_media_types = {entry["mediaType"] for entry in manifest["manifests"]}
216
+
217
+ self.assertEqual(manifest["mediaType"], MEDIA_TYPE.MANIFEST_LIST)
218
+ self.assertIn(MEDIA_TYPE.MANIFEST_V2, entry_media_types)
219
+ self.assertIn(MEDIA_TYPE.MANIFEST_OCI, entry_media_types)
220
+
221
+ try:
222
+ validate_manifest(
223
+ manifest,
224
+ MEDIA_TYPE.MANIFEST_LIST,
225
+ "sha256:31b31269d06603366cbfd0284708dcd2e281e8a4188e53fce3d3304439d0df3d",
226
+ )
227
+ except ManifestInvalid:
228
+ self.fail()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pulp-container
3
- Version: 2.28.0
3
+ Version: 2.28.1
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.115,>=3.111.0
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
@@ -143,4 +143,5 @@ pulp_container/tests/unit/__init__.py
143
143
  pulp_container/tests/unit/test_json_schemas.py
144
144
  pulp_container/tests/unit/test_models.py
145
145
  pulp_container/tests/unit/test_serializers.py
146
- pulp_container/tests/unit/test_sync_stages.py
146
+ pulp_container/tests/unit/test_sync_stages.py
147
+ pulp_container/tests/unit/fixtures/ryuk_0.13.0_manifest_list.json
@@ -1,4 +1,4 @@
1
1
  jsonschema<4.27,>=4.4
2
- pulpcore<3.115,>=3.111.0
2
+ pulpcore<3.130,>=3.111.0
3
3
  pyjwt[crypto]<2.14,>=2.4
4
4
  pysequoia<0.2.0,>=0.1.33
@@ -7,7 +7,7 @@ build-backend = 'setuptools.build_meta'
7
7
 
8
8
  [project]
9
9
  name = "pulp-container"
10
- version = "2.28.0"
10
+ version = "2.28.1"
11
11
  description = "Container plugin for the Pulp Project"
12
12
  readme = "README.md"
13
13
  authors = [
@@ -24,7 +24,7 @@ classifiers=[
24
24
  requires-python = ">=3.11"
25
25
  dependencies = [
26
26
  "jsonschema>=4.4,<4.27",
27
- "pulpcore>=3.111.0,<3.115",
27
+ "pulpcore>=3.111.0,<3.130",
28
28
  "pyjwt[crypto]>=2.4,<2.14",
29
29
  "pysequoia>=0.1.33,<0.2.0"
30
30
  ]
@@ -89,7 +89,7 @@ ignore = [
89
89
  [tool.bumpversion]
90
90
  # This section is managed by the plugin template. Do not edit manually.
91
91
 
92
- current_version = "2.28.0"
92
+ current_version = "2.28.1"
93
93
  commit = false
94
94
  tag = false
95
95
  parse = "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<alpha>0a)?(?P<patch>\\d+)(\\.(?P<release>[a-z]+))?"
@@ -135,7 +135,6 @@ filename = "./pyproject.toml"
135
135
  search = "version = \"{current_version}\""
136
136
  replace = "version = \"{new_version}\""
137
137
 
138
-
139
138
  [tool.ruff]
140
139
  # This section is managed by the plugin template. Do not edit manually.
141
140
  line-length = 100
@@ -156,6 +155,7 @@ extend-select = [
156
155
  [tool.ruff.lint.flake8-tidy-imports.banned-api]
157
156
  # This section is managed by the plugin template. Do not edit manually.
158
157
  "distutils".msg = "The 'distutils' module has been deprecated since Python 3.9."
158
+ "pulpcore.app.settings".msg = "Always import 'settings' from 'django.conf' instead."
159
159
  "pulpcore.app".msg = "The 'pulpcore' apis must only be consumed via 'pulpcore.plugin'."
160
160
 
161
161
  [tool.ruff.lint.isort]
File without changes