pulp-container 2.26.18__tar.gz → 2.26.20__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.26.18 → pulp_container-2.26.20}/CHANGES.md +18 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/PKG-INFO +1 -1
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/__init__.py +1 -1
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/downloaders.py +46 -23
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/models.py +3 -4
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/registry_api.py +1 -1
- pulp_container-2.26.20/pulp_container/tests/unit/test_downloaders.py +33 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container.egg-info/PKG-INFO +1 -1
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container.egg-info/SOURCES.txt +1 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pyproject.toml +2 -2
- {pulp_container-2.26.18 → pulp_container-2.26.20}/COMMITMENT +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/COPYRIGHT +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/LICENSE +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/MANIFEST.in +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/README.rst +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/functest_requirements.txt +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/__init__.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/access_policy.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/authorization.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/cache.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/checks.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/content.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/exceptions.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/fields.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/global_access_conditions.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/json_schemas.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/management/__init__.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/management/commands/__init__.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/management/commands/container-handle-image-data.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/management/commands/container-repair-media-type.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/management/commands/container-repair-pull-through-distributions.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/migrations/0001_initial.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/migrations/0001_squashed_0032_upload_artifact.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/migrations/0002_containerrepository.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/migrations/0003_oci_mediatype.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/migrations/0004_upload.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/migrations/0005_contentredirectcontentguard.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/migrations/0006_containerpushrepository.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/migrations/0007_clear_tags_artifacts_refs.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/migrations/0008_include_exclude_tags.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/migrations/0009_container_namespace.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/migrations/0010_remove_uploadchunk.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/migrations/0011_add_container_repository_permissions.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/migrations/0012_add_container_namespace_permissions.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/migrations/0013_add_pull_push_permissions.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/migrations/0014_containerdistribution_private.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/migrations/0015_manage_tags_push_repo.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/migrations/0016_add_delete_versions_permission.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/migrations/0017_add_granular_perms.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/migrations/0018_containerdistribution_description.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/migrations/0019_DATA_distribution_model_swap.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/migrations/0020_update_push_repo_perms.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/migrations/0021_data_move_redirect_content_guard_to_core.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/migrations/0022_delete_contentredirectcontentguard.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/migrations/0023_manifestsignature.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/migrations/0024_containerremote_sigstore.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/migrations/0025_signature_stored_in_textfield.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/migrations/0026_manifest_signing_service.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/migrations/0027_data_translate_perms_to_roles.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/migrations/0028_add_role_manage_permissions.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/migrations/0029_remove_blob_media_type.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/migrations/0030_enforce_tagged_manifest_reference.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/migrations/0031_replace_charf_with_textf.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/migrations/0032_upload_artifact.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/migrations/0033_raise_warning_for_repair.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/migrations/0034_translate_signed_schema.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/migrations/0035_alter_blob_content_ptr_and_more.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/migrations/0036_containerpushrepository_pending_blobs_manifests.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/migrations/0037_create_pull_through_cache_models.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/migrations/0038_add_manifest_metadata_fields.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/migrations/0039_manifest_data.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/migrations/0040_add_remote_repo_filter.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/migrations/0041_add_pull_through_pull_permissions.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/migrations/0042_add_manifest_nature_field.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/migrations/0043_add_os_arch_image_size_manifest_fields.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/migrations/0044_add_domain.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/migrations/0045_alter_manifest_compressed_image_size.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/migrations/__init__.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/modelresource.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/pull_through.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/redirects.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/registry.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/replica.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/serializers.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/settings.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/tasks/__init__.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/tasks/builder.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/tasks/download_image_data.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/tasks/recursive_add.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/tasks/recursive_remove.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/tasks/sign.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/tasks/sync_stages.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/tasks/synchronize.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/tasks/tag.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/tasks/untag.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/token_verification.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/urls.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/utils.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/viewsets.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/webserver_snippets/__init__.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/webserver_snippets/apache.conf +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/webserver_snippets/nginx.conf +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/constants.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/tests/__init__.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/tests/functional/__init__.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/tests/functional/api/__init__.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/tests/functional/api/test_build_images.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/tests/functional/api/test_content_cache.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/tests/functional/api/test_crud_distributions.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/tests/functional/api/test_crud_remotes.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/tests/functional/api/test_domains.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/tests/functional/api/test_flatpak.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/tests/functional/api/test_pull_content.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/tests/functional/api/test_pull_through_cache.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/tests/functional/api/test_pulpimportexport.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/tests/functional/api/test_push_content.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/tests/functional/api/test_push_signatures.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/tests/functional/api/test_rbac_push_repositories.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/tests/functional/api/test_rbac_remotes.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/tests/functional/api/test_rbac_repo_content.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/tests/functional/api/test_rbac_repo_versions.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/tests/functional/api/test_rbac_sync_repositories.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/tests/functional/api/test_recursive_add.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/tests/functional/api/test_recursive_remove.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/tests/functional/api/test_remote_filter_pull_through.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/tests/functional/api/test_repositories_list.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/tests/functional/api/test_sign_manifests.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/tests/functional/api/test_sync.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/tests/functional/api/test_sync_signatures.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/tests/functional/api/test_tagging_images.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/tests/functional/api/test_token_authentication.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/tests/functional/conftest.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/tests/functional/constants.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/tests/functional/utils.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/tests/unit/__init__.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/tests/unit/fixtures/ryuk_0.13.0_manifest_list.json +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/tests/unit/test_json_schemas.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/tests/unit/test_models.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/tests/unit/test_pull_through_repair.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/tests/unit/test_serializers.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/tests/unit/test_sync_stages.py +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container.egg-info/dependency_links.txt +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container.egg-info/entry_points.txt +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container.egg-info/requires.txt +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container.egg-info/top_level.txt +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/setup.cfg +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/test_requirements.txt +0 -0
- {pulp_container-2.26.18 → pulp_container-2.26.20}/unittest_requirements.txt +0 -0
|
@@ -8,6 +8,24 @@
|
|
|
8
8
|
|
|
9
9
|
[//]: # (towncrier release notes start)
|
|
10
10
|
|
|
11
|
+
## 2.26.20 (2026-10-28) {: #2.26.20 }
|
|
12
|
+
|
|
13
|
+
#### Bugfixes {: #2.26.20-bugfix }
|
|
14
|
+
|
|
15
|
+
- Container blob downloads now respect each Domain's object storage redirect setting.
|
|
16
|
+
- Fixed pull-through signature lookups failing with a 500 when the upstream registry (e.g. gcr.io) sends unquoted values in its bearer auth challenge.
|
|
17
|
+
- Fixed the registry Authorization header leaking into a shared module-level headers dict, which could send one remote's credentials to another registry.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## 2.26.19 (2026-10-08) {: #2.26.19 }
|
|
22
|
+
|
|
23
|
+
#### Bugfixes {: #2.26.19-bugfix }
|
|
24
|
+
|
|
25
|
+
- Fixed global auth token leakage. CVE-2026-103868
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
11
29
|
## 2.26.18 (2026-10-07) {: #2.26.18 }
|
|
12
30
|
|
|
13
31
|
No significant changes.
|
|
@@ -27,15 +27,12 @@ class RegistryAuthHttpDownloader(HttpDownloader):
|
|
|
27
27
|
Additionally, use custom headers from DeclarativeArtifact.extra_data['headers']
|
|
28
28
|
"""
|
|
29
29
|
|
|
30
|
-
registry_auth = {"bearer": None, "basic": None}
|
|
31
|
-
token_lock = asyncio.Lock()
|
|
32
|
-
|
|
33
30
|
def __init__(self, *args, **kwargs):
|
|
34
31
|
"""
|
|
35
32
|
Initialize the downloader.
|
|
36
33
|
"""
|
|
37
34
|
self.remote = kwargs.pop("remote")
|
|
38
|
-
|
|
35
|
+
self.factory = kwargs.pop("factory")
|
|
39
36
|
super().__init__(*args, **kwargs)
|
|
40
37
|
|
|
41
38
|
async def _run(self, handle_401=True, extra_data=None):
|
|
@@ -60,11 +57,11 @@ class RegistryAuthHttpDownloader(HttpDownloader):
|
|
|
60
57
|
headers = V2_ACCEPT_HEADERS
|
|
61
58
|
repo_name = None
|
|
62
59
|
if extra_data is not None:
|
|
63
|
-
headers = extra_data.get("headers", headers)
|
|
60
|
+
headers = dict(extra_data.get("headers", headers))
|
|
64
61
|
repo_name = extra_data.get("repo_name", None)
|
|
65
62
|
http_method = extra_data.get("http_method", "get") if extra_data is not None else "get"
|
|
66
|
-
this_token = self.registry_auth["bearer"]
|
|
67
|
-
basic_auth = self.registry_auth["basic"]
|
|
63
|
+
this_token = self.factory.registry_auth["bearer"]
|
|
64
|
+
basic_auth = self.factory.registry_auth["basic"]
|
|
68
65
|
auth_headers = self.auth_header(this_token, basic_auth)
|
|
69
66
|
headers.update(auth_headers)
|
|
70
67
|
# aiohttps does not allow to send auth argument and auth header together
|
|
@@ -87,16 +84,16 @@ class RegistryAuthHttpDownloader(HttpDownloader):
|
|
|
87
84
|
if "bearer" in response_auth_header.lower():
|
|
88
85
|
# Token has not been updated during request
|
|
89
86
|
if (
|
|
90
|
-
self.registry_auth["bearer"] is None
|
|
91
|
-
or self.registry_auth["bearer"] == this_token
|
|
87
|
+
self.factory.registry_auth["bearer"] is None
|
|
88
|
+
or self.factory.registry_auth["bearer"] == this_token
|
|
92
89
|
):
|
|
93
|
-
self.registry_auth["bearer"] = None
|
|
90
|
+
self.factory.registry_auth["bearer"] = None
|
|
94
91
|
await self.update_token(response_auth_header, this_token, repo_name)
|
|
95
92
|
return await self._run(handle_401=False, extra_data=extra_data)
|
|
96
93
|
elif "basic" in response_auth_header.lower():
|
|
97
94
|
if self.remote.username:
|
|
98
95
|
basic = aiohttp.BasicAuth(self.remote.username, self.remote.password)
|
|
99
|
-
self.registry_auth["basic"] = basic.encode()
|
|
96
|
+
self.factory.registry_auth["basic"] = basic.encode()
|
|
100
97
|
return await self._run(handle_401=False, extra_data=extra_data)
|
|
101
98
|
else:
|
|
102
99
|
raise
|
|
@@ -117,21 +114,14 @@ class RegistryAuthHttpDownloader(HttpDownloader):
|
|
|
117
114
|
"""
|
|
118
115
|
Update the Bearer token to be used with all requests.
|
|
119
116
|
"""
|
|
120
|
-
async with self.token_lock:
|
|
117
|
+
async with self.factory.token_lock:
|
|
121
118
|
if (
|
|
122
|
-
self.registry_auth["bearer"] is not None
|
|
123
|
-
and self.registry_auth["bearer"] == used_token
|
|
119
|
+
self.factory.registry_auth["bearer"] is not None
|
|
120
|
+
and self.factory.registry_auth["bearer"] == used_token
|
|
124
121
|
):
|
|
125
122
|
return
|
|
126
123
|
log.info("Updating bearer token")
|
|
127
|
-
|
|
128
|
-
bearer_info_list = re.split(",(?=[^=,]+=)", bearer_info_string)
|
|
129
|
-
|
|
130
|
-
# The remaining string consists of comma seperated key=value pairs
|
|
131
|
-
auth_query_dict = {}
|
|
132
|
-
for key, value in (item.split("=") for item in bearer_info_list):
|
|
133
|
-
# The value is a string within a string, ex: '"value"'
|
|
134
|
-
auth_query_dict[key] = json.loads(value)
|
|
124
|
+
auth_query_dict = self.parse_auth_challenge(response_auth_header)
|
|
135
125
|
try:
|
|
136
126
|
token_base_url = auth_query_dict.pop("realm")
|
|
137
127
|
except KeyError:
|
|
@@ -163,7 +153,25 @@ class RegistryAuthHttpDownloader(HttpDownloader):
|
|
|
163
153
|
|
|
164
154
|
token_js = json.loads(token_data)
|
|
165
155
|
token = token_js.get("token") or token_js.get("access_token")
|
|
166
|
-
self.registry_auth["bearer"] = token
|
|
156
|
+
self.factory.registry_auth["bearer"] = token
|
|
157
|
+
|
|
158
|
+
@staticmethod
|
|
159
|
+
def parse_auth_challenge(response_auth_header):
|
|
160
|
+
"""
|
|
161
|
+
Parse the parameters of a Bearer auth challenge into a dictionary.
|
|
162
|
+
|
|
163
|
+
Values may be quoted strings or plain tokens (RFC 7235), e.g. gcr.io responds with
|
|
164
|
+
'Bearer realm="https://gcr.io/v2/token",service=gcr.io'.
|
|
165
|
+
"""
|
|
166
|
+
bearer_info_string = response_auth_header[len("Bearer ") :]
|
|
167
|
+
auth_query_dict = {}
|
|
168
|
+
for match in re.finditer(r'([^=,\s]+)=(?:"((?:[^"\\]|\\.)*)"|([^,]*))', bearer_info_string):
|
|
169
|
+
key, quoted, plain = match.groups()
|
|
170
|
+
if quoted is not None:
|
|
171
|
+
auth_query_dict[key] = re.sub(r"\\(.)", r"\1", quoted)
|
|
172
|
+
else:
|
|
173
|
+
auth_query_dict[key] = plain.strip()
|
|
174
|
+
return auth_query_dict
|
|
167
175
|
|
|
168
176
|
@staticmethod
|
|
169
177
|
def auth_header(token, basic_auth):
|
|
@@ -193,6 +201,21 @@ class RegistryAuthHttpDownloader(HttpDownloader):
|
|
|
193
201
|
)
|
|
194
202
|
|
|
195
203
|
|
|
204
|
+
class RegistryAuthDownloaderFactory(DownloaderFactory):
|
|
205
|
+
"""
|
|
206
|
+
A downloader factory for registry access that can also share the authentication tokens.
|
|
207
|
+
"""
|
|
208
|
+
|
|
209
|
+
def __init__(self, *args, **kwargs):
|
|
210
|
+
super().__init__(*args, **kwargs)
|
|
211
|
+
self.registry_auth = {"bearer": None, "basic": None}
|
|
212
|
+
self.token_lock = asyncio.Lock()
|
|
213
|
+
|
|
214
|
+
def _http_or_https(self, download_class, url, **kwargs):
|
|
215
|
+
kwargs.setdefault("factory", self)
|
|
216
|
+
return super()._http_or_https(download_class, url, **kwargs)
|
|
217
|
+
|
|
218
|
+
|
|
196
219
|
class NoAuthSignatureDownloader(HttpDownloader):
|
|
197
220
|
"""A downloader class suited for signature downloads."""
|
|
198
221
|
|
|
@@ -12,7 +12,6 @@ from django.shortcuts import redirect
|
|
|
12
12
|
from django_lifecycle import AFTER_CREATE, AFTER_DELETE, AFTER_UPDATE, hook
|
|
13
13
|
|
|
14
14
|
from pulpcore.plugin.cache import SyncContentCache
|
|
15
|
-
from pulpcore.plugin.download import DownloaderFactory
|
|
16
15
|
from pulpcore.plugin.models import (
|
|
17
16
|
Artifact,
|
|
18
17
|
AutoAddObjPermsMixin,
|
|
@@ -498,17 +497,17 @@ class ContainerRemote(Remote, AutoAddObjPermsMixin):
|
|
|
498
497
|
"""
|
|
499
498
|
Downloader Factory that maps to custom downloaders which support registry auth.
|
|
500
499
|
|
|
501
|
-
Upon first access, the
|
|
500
|
+
Upon first access, the RegistryAuthDownloaderFactory is instantiated and saved internally.
|
|
502
501
|
|
|
503
502
|
Returns:
|
|
504
|
-
DownloadFactory: The instantiated
|
|
503
|
+
DownloadFactory: The instantiated RegistryAuthDownloaderFactory to be used by
|
|
505
504
|
get_downloader()
|
|
506
505
|
|
|
507
506
|
"""
|
|
508
507
|
try:
|
|
509
508
|
return self._download_factory
|
|
510
509
|
except AttributeError:
|
|
511
|
-
self._download_factory =
|
|
510
|
+
self._download_factory = downloaders.RegistryAuthDownloaderFactory(
|
|
512
511
|
self,
|
|
513
512
|
downloader_overrides={
|
|
514
513
|
"http": downloaders.RegistryAuthHttpDownloader,
|
|
@@ -1031,7 +1031,7 @@ class RedirectsMixin:
|
|
|
1031
1031
|
domain = get_domain()
|
|
1032
1032
|
if (
|
|
1033
1033
|
domain.storage_class == "pulpcore.app.models.storage.FileSystem"
|
|
1034
|
-
or not
|
|
1034
|
+
or not domain.redirect_to_object_storage
|
|
1035
1035
|
):
|
|
1036
1036
|
self.redirects_class = FileStorageRedirects
|
|
1037
1037
|
elif domain.storage_class == "storages.backends.s3boto3.S3Boto3Storage":
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
|
|
3
|
+
from pulp_container.app.downloaders import RegistryAuthHttpDownloader
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@pytest.mark.parametrize(
|
|
7
|
+
"header,expected",
|
|
8
|
+
[
|
|
9
|
+
(
|
|
10
|
+
'Bearer realm="https://auth.docker.io/token",service="registry.docker.io"',
|
|
11
|
+
{"realm": "https://auth.docker.io/token", "service": "registry.docker.io"},
|
|
12
|
+
),
|
|
13
|
+
(
|
|
14
|
+
'Bearer realm="https://gcr.io/v2/token",service=gcr.io',
|
|
15
|
+
{"realm": "https://gcr.io/v2/token", "service": "gcr.io"},
|
|
16
|
+
),
|
|
17
|
+
(
|
|
18
|
+
'Bearer realm="https://quay.io/v2/auth",service="quay.io",'
|
|
19
|
+
'scope="repository:foo/bar:pull,push"',
|
|
20
|
+
{
|
|
21
|
+
"realm": "https://quay.io/v2/auth",
|
|
22
|
+
"service": "quay.io",
|
|
23
|
+
"scope": "repository:foo/bar:pull,push",
|
|
24
|
+
},
|
|
25
|
+
),
|
|
26
|
+
(
|
|
27
|
+
'Bearer realm="https://example.com/token", service=example.com, error="a \\"b\\""',
|
|
28
|
+
{"realm": "https://example.com/token", "service": "example.com", "error": 'a "b"'},
|
|
29
|
+
),
|
|
30
|
+
],
|
|
31
|
+
)
|
|
32
|
+
def test_parse_auth_challenge(header, expected):
|
|
33
|
+
assert RegistryAuthHttpDownloader.parse_auth_challenge(header) == expected
|
|
@@ -137,6 +137,7 @@ pulp_container/tests/functional/api/test_sync_signatures.py
|
|
|
137
137
|
pulp_container/tests/functional/api/test_tagging_images.py
|
|
138
138
|
pulp_container/tests/functional/api/test_token_authentication.py
|
|
139
139
|
pulp_container/tests/unit/__init__.py
|
|
140
|
+
pulp_container/tests/unit/test_downloaders.py
|
|
140
141
|
pulp_container/tests/unit/test_json_schemas.py
|
|
141
142
|
pulp_container/tests/unit/test_models.py
|
|
142
143
|
pulp_container/tests/unit/test_pull_through_repair.py
|
|
@@ -7,7 +7,7 @@ build-backend = 'setuptools.build_meta'
|
|
|
7
7
|
|
|
8
8
|
[project]
|
|
9
9
|
name = "pulp-container"
|
|
10
|
-
version = "2.26.
|
|
10
|
+
version = "2.26.20"
|
|
11
11
|
description = "Container plugin for the Pulp Project"
|
|
12
12
|
readme = "README.md"
|
|
13
13
|
authors = [
|
|
@@ -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.26.
|
|
92
|
+
current_version = "2.26.20"
|
|
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]+))?"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/global_access_conditions.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/management/commands/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/migrations/0001_initial.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/migrations/0004_upload.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/migrations/0044_add_domain.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/tasks/download_image_data.py
RENAMED
|
File without changes
|
|
File without changes
|
{pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/tasks/recursive_remove.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/webserver_snippets/__init__.py
RENAMED
|
File without changes
|
{pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/webserver_snippets/apache.conf
RENAMED
|
File without changes
|
{pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/app/webserver_snippets/nginx.conf
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/tests/functional/__init__.py
RENAMED
|
File without changes
|
{pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/tests/functional/api/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/tests/functional/api/test_sync.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/tests/functional/conftest.py
RENAMED
|
File without changes
|
{pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/tests/functional/constants.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/tests/unit/test_json_schemas.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/tests/unit/test_serializers.py
RENAMED
|
File without changes
|
{pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container/tests/unit/test_sync_stages.py
RENAMED
|
File without changes
|
{pulp_container-2.26.18 → pulp_container-2.26.20}/pulp_container.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|