pulp-python 3.30.2__tar.gz → 3.31.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_python-3.30.2 → pulp_python-3.31.0}/CHANGES.md +50 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/PKG-INFO +1 -1
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/app/__init__.py +1 -1
- pulp_python-3.31.0/pulp_python/app/exceptions.py +54 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/app/models.py +5 -5
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/app/pypi/views.py +12 -12
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/app/serializers.py +4 -3
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/app/tasks/sync.py +7 -6
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/app/tasks/upload.py +11 -2
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/app/utils.py +12 -8
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/tests/functional/api/test_domains.py +8 -2
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python.egg-info/PKG-INFO +1 -1
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python.egg-info/SOURCES.txt +1 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pyproject.toml +2 -2
- {pulp_python-3.30.2 → pulp_python-3.31.0}/COMMITMENT +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/COPYRIGHT +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/LICENSE +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/MANIFEST.in +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/README.md +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/functest_requirements.txt +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/__init__.py +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/app/global_access_conditions.py +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/app/management/__init__.py +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/app/management/commands/__init__.py +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/app/management/commands/repair-python-metadata.py +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/app/migrations/0001_initial.py +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/app/migrations/0001_squashed_0010_update_json_field.py +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/app/migrations/0002_pythonpackagecontent_python_version.py +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/app/migrations/0003_new_sync_filters.py +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/app/migrations/0004_DATA_swap_distribution_model.py +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/app/migrations/0005_pythonpackagecontent_sha256.py +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/app/migrations/0006_pythonrepository_autopublish.py +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/app/migrations/0007_pythonpackagecontent_mv-2-1.py +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/app/migrations/0008_pythonpackagecontent_unique_sha256.py +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/app/migrations/0009_pythondistribution_allow_uploads.py +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/app/migrations/0010_update_json_field.py +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/app/migrations/0011_alter_pythondistribution_distribution_ptr_and_more.py +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/app/migrations/0012_add_domain.py +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/app/migrations/0013_add_rbac_permissions.py +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/app/migrations/0014_pythonpackagecontent_dynamic_and_more.py +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/app/migrations/0015_alter_pythonpackagecontent_options.py +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/app/migrations/0016_pythonpackagecontent_metadata_sha256.py +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/app/migrations/0017_pythonpackagecontent_size.py +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/app/migrations/0018_packageprovenance.py +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/app/migrations/0019_create_missing_metadata_artifacts.py +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/app/migrations/0020_pythonpackagecontent_name_normalized.py +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/app/migrations/0021_pythonrepository_upload_duplicate_filenames.py +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/app/migrations/0022_pythonblocklistentry.py +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/app/migrations/__init__.py +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/app/modelresource.py +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/app/provenance.py +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/app/pypi/__init__.py +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/app/pypi/serializers.py +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/app/replica.py +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/app/settings.py +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/app/tasks/__init__.py +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/app/tasks/publish.py +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/app/tasks/repair.py +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/app/tasks/vulnerability_report.py +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/app/urls.py +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/app/viewsets.py +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/app/webserver_snippets/__init__.py +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/app/webserver_snippets/apache.conf +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/app/webserver_snippets/nginx.conf +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/pytest_plugin.py +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/tests/__init__.py +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/tests/functional/__init__.py +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/tests/functional/api/__init__.py +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/tests/functional/api/test_attestations.py +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/tests/functional/api/test_auto_publish.py +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/tests/functional/api/test_blocklist.py +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/tests/functional/api/test_consume_content.py +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/tests/functional/api/test_crud_content_unit.py +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/tests/functional/api/test_crud_publications.py +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/tests/functional/api/test_crud_remotes.py +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/tests/functional/api/test_download_content.py +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/tests/functional/api/test_export_import.py +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/tests/functional/api/test_full_mirror.py +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/tests/functional/api/test_pypi_apis.py +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/tests/functional/api/test_pypi_simple_api.py +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/tests/functional/api/test_rbac.py +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/tests/functional/api/test_repair.py +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/tests/functional/api/test_sync.py +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/tests/functional/api/test_upload.py +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/tests/functional/api/test_vulnerability_report.py +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/tests/functional/assets/shelf-reader-0.1.tar.gz.publish.attestation +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/tests/functional/assets/shelf_reader-0.1-py2-none-any.whl.publish.attestation +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/tests/functional/constants.py +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/tests/functional/utils.py +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/tests/unit/__init__.py +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/tests/unit/test_models.py +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python.egg-info/dependency_links.txt +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python.egg-info/entry_points.txt +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python.egg-info/requires.txt +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python.egg-info/top_level.txt +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/setup.cfg +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/test_requirements.txt +0 -0
- {pulp_python-3.30.2 → pulp_python-3.31.0}/unittest_requirements.txt +0 -0
|
@@ -8,6 +8,36 @@
|
|
|
8
8
|
|
|
9
9
|
[//]: # (towncrier release notes start)
|
|
10
10
|
|
|
11
|
+
## 3.31.0 (2026-06-09) {: #3.31.0 }
|
|
12
|
+
|
|
13
|
+
#### Features {: #3.31.0-feature }
|
|
14
|
+
|
|
15
|
+
- Add more Pulp Exceptions.
|
|
16
|
+
|
|
17
|
+
#### Bugfixes {: #3.31.0-bugfix }
|
|
18
|
+
|
|
19
|
+
- Fixed `upload_time` in Simple and JSON APIs to reflect repository addition time instead of content creation time.
|
|
20
|
+
[#1232](https://github.com/pulp/pulp_python/issues/1232)
|
|
21
|
+
- Fixed blocklist entries API to support `isnull` filter lookup on `version` to uniquely identify name-only entries.
|
|
22
|
+
[#1238](https://github.com/pulp/pulp_python/issues/1238)
|
|
23
|
+
- Optimized `upload_time` lookups in Simple and JSON APIs.
|
|
24
|
+
[#1242](https://github.com/pulp/pulp_python/issues/1242)
|
|
25
|
+
- Optimized `provenance` lookups in Simple API.
|
|
26
|
+
[#1243](https://github.com/pulp/pulp_python/issues/1243)
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## 3.30.3 (2026-06-05) {: #3.30.3 }
|
|
31
|
+
|
|
32
|
+
#### Bugfixes {: #3.30.3-bugfix }
|
|
33
|
+
|
|
34
|
+
- Optimized `upload_time` lookups in Simple and JSON APIs.
|
|
35
|
+
[#1242](https://github.com/pulp/pulp_python/issues/1242)
|
|
36
|
+
- Optimized `provenance` lookups in Simple API.
|
|
37
|
+
[#1243](https://github.com/pulp/pulp_python/issues/1243)
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
11
41
|
## 3.30.2 (2026-05-19) {: #3.30.2 }
|
|
12
42
|
|
|
13
43
|
#### Bugfixes {: #3.30.2-bugfix }
|
|
@@ -89,6 +119,26 @@
|
|
|
89
119
|
|
|
90
120
|
---
|
|
91
121
|
|
|
122
|
+
## 3.27.4 (2026-06-05) {: #3.27.4 }
|
|
123
|
+
|
|
124
|
+
#### Bugfixes {: #3.27.4-bugfix }
|
|
125
|
+
|
|
126
|
+
- Optimized `upload_time` lookups in Simple and JSON APIs.
|
|
127
|
+
[#1242](https://github.com/pulp/pulp_python/issues/1242)
|
|
128
|
+
- Optimized `provenance` lookups in Simple API.
|
|
129
|
+
[#1243](https://github.com/pulp/pulp_python/issues/1243)
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## 3.27.3 (2026-05-19) {: #3.27.3 }
|
|
134
|
+
|
|
135
|
+
#### Bugfixes {: #3.27.3-bugfix }
|
|
136
|
+
|
|
137
|
+
- Fixed `upload_time` in Simple and JSON APIs to reflect repository addition time instead of content creation time.
|
|
138
|
+
[#1232](https://github.com/pulp/pulp_python/issues/1232)
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
92
142
|
## 3.27.2 (2026-04-14) {: #3.27.2 }
|
|
93
143
|
|
|
94
144
|
#### Bugfixes {: #3.27.2-bugfix }
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
from gettext import gettext as _
|
|
2
|
+
|
|
3
|
+
from pulpcore.plugin.exceptions import PulpException
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class AttestationVerificationError(PulpException):
|
|
7
|
+
"""
|
|
8
|
+
Raised when attestation verification fails.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
error_code = "PYT0001"
|
|
12
|
+
|
|
13
|
+
def __init__(self, message):
|
|
14
|
+
super().__init__()
|
|
15
|
+
self.message = message
|
|
16
|
+
|
|
17
|
+
def __str__(self):
|
|
18
|
+
return f"[{self.error_code}] " + _("Attestation verification failed: {message}").format(
|
|
19
|
+
message=self.message
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class UnsupportedProtocolError(PulpException):
|
|
24
|
+
"""
|
|
25
|
+
Raised when an unsupported protocol is used for syncing.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
error_code = "PYT0002"
|
|
29
|
+
|
|
30
|
+
def __init__(self, protocol):
|
|
31
|
+
super().__init__()
|
|
32
|
+
self.protocol = protocol
|
|
33
|
+
|
|
34
|
+
def __str__(self):
|
|
35
|
+
return f"[{self.error_code}] " + _(
|
|
36
|
+
"Only HTTP(S) is supported for python syncing, got: {protocol}"
|
|
37
|
+
).format(protocol=self.protocol)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class InvalidAttestationsError(PulpException):
|
|
41
|
+
"""
|
|
42
|
+
Raised when attestation data cannot be validated.
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
error_code = "PYT0003"
|
|
46
|
+
|
|
47
|
+
def __init__(self, message):
|
|
48
|
+
super().__init__()
|
|
49
|
+
self.message = message
|
|
50
|
+
|
|
51
|
+
def __str__(self):
|
|
52
|
+
return f"[{self.error_code}] " + _("Invalid attestations: {message}").format(
|
|
53
|
+
message=self.message
|
|
54
|
+
)
|
|
@@ -412,16 +412,16 @@ class PythonRepository(Repository, AutoAddObjPermsMixin):
|
|
|
412
412
|
|
|
413
413
|
def _check_for_package_substitution(self, new_version):
|
|
414
414
|
"""
|
|
415
|
-
Raise a ValidationError if newly added packages would replace existing packages
|
|
416
|
-
the same filename but a different sha256 checksum.
|
|
415
|
+
Raise a ValidationError if newly added packages would replace existing packages
|
|
416
|
+
that have the same filename but a different sha256 checksum.
|
|
417
417
|
"""
|
|
418
418
|
qs = PythonPackageContent.objects.filter(pk__in=new_version.content)
|
|
419
419
|
duplicates = collect_duplicates(qs, ("filename",))
|
|
420
420
|
if duplicates:
|
|
421
421
|
raise ValidationError(
|
|
422
|
-
"Found duplicate packages being added with the same filename but different
|
|
423
|
-
"To allow this, set 'allow_package_substitution' to True on the
|
|
424
|
-
f"Conflicting packages: {duplicates}"
|
|
422
|
+
"Found duplicate packages being added with the same filename but different "
|
|
423
|
+
"checksums. To allow this, set 'allow_package_substitution' to True on the "
|
|
424
|
+
f"repository. Conflicting packages: {duplicates}"
|
|
425
425
|
)
|
|
426
426
|
|
|
427
427
|
def _check_blocklist(self, new_version):
|
|
@@ -7,7 +7,7 @@ from urllib.parse import urljoin, urlparse, urlunsplit
|
|
|
7
7
|
from django.contrib.sessions.models import Session
|
|
8
8
|
from django.core.exceptions import ObjectDoesNotExist
|
|
9
9
|
from django.db import transaction
|
|
10
|
-
from django.db.models import OuterRef,
|
|
10
|
+
from django.db.models import Exists, F, FilteredRelation, OuterRef, Q
|
|
11
11
|
from django.db.utils import DatabaseError
|
|
12
12
|
from django.http.response import (
|
|
13
13
|
Http404,
|
|
@@ -26,7 +26,6 @@ from rest_framework.renderers import BrowsableAPIRenderer, JSONRenderer, Templat
|
|
|
26
26
|
from rest_framework.response import Response
|
|
27
27
|
from rest_framework.viewsets import ViewSet
|
|
28
28
|
|
|
29
|
-
from pulpcore.plugin.models import RepositoryContent
|
|
30
29
|
from pulpcore.plugin.tasking import dispatch
|
|
31
30
|
from pulpcore.plugin.util import get_domain, get_url
|
|
32
31
|
from pulpcore.plugin.viewsets import OperationPostponedResponse
|
|
@@ -368,13 +367,16 @@ class SimpleView(PackageUploadMixin, ViewSet):
|
|
|
368
367
|
return redirect(urljoin(self.base_content_url, f"{path}/simple/{normalized}/"))
|
|
369
368
|
if content is not None:
|
|
370
369
|
local_packages = content.filter(name_normalized=normalized)
|
|
371
|
-
repo_added_subquery = RepositoryContent.objects.filter(
|
|
372
|
-
content_id=OuterRef("pk"),
|
|
373
|
-
repository=repo_ver.repository,
|
|
374
|
-
version_removed=None,
|
|
375
|
-
).values("pulp_created")[:1]
|
|
376
370
|
packages = local_packages.annotate(
|
|
377
|
-
|
|
371
|
+
active_membership=FilteredRelation(
|
|
372
|
+
"version_memberships",
|
|
373
|
+
condition=Q(
|
|
374
|
+
version_memberships__repository=repo_ver.repository,
|
|
375
|
+
version_memberships__version_removed=None,
|
|
376
|
+
),
|
|
377
|
+
),
|
|
378
|
+
repo_added_time=F("active_membership__pulp_created"),
|
|
379
|
+
has_provenance=Exists(PackageProvenance.objects.filter(package_id=OuterRef("pk"))),
|
|
378
380
|
).values(
|
|
379
381
|
"filename",
|
|
380
382
|
"sha256",
|
|
@@ -383,9 +385,7 @@ class SimpleView(PackageUploadMixin, ViewSet):
|
|
|
383
385
|
"size",
|
|
384
386
|
"repo_added_time",
|
|
385
387
|
"version",
|
|
386
|
-
|
|
387
|
-
provenances = PackageProvenance.objects.filter(package__in=local_packages).values_list(
|
|
388
|
-
"package__filename", flat=True
|
|
388
|
+
"has_provenance",
|
|
389
389
|
)
|
|
390
390
|
local_releases = {
|
|
391
391
|
p["filename"]: {
|
|
@@ -394,7 +394,7 @@ class SimpleView(PackageUploadMixin, ViewSet):
|
|
|
394
394
|
"upload_time": p["repo_added_time"],
|
|
395
395
|
"provenance": (
|
|
396
396
|
self.get_provenance_url(normalized, p["version"], p["filename"])
|
|
397
|
-
if p["
|
|
397
|
+
if p["has_provenance"]
|
|
398
398
|
else None
|
|
399
399
|
),
|
|
400
400
|
}
|
|
@@ -9,7 +9,8 @@ from django.db.utils import IntegrityError
|
|
|
9
9
|
from drf_spectacular.utils import extend_schema_serializer
|
|
10
10
|
from packaging.requirements import Requirement
|
|
11
11
|
from packaging.version import InvalidVersion, Version
|
|
12
|
-
from pydantic import TypeAdapter
|
|
12
|
+
from pydantic import TypeAdapter
|
|
13
|
+
from pydantic import ValidationError as PydanticValidationError
|
|
13
14
|
from pypi_attestations import AttestationError
|
|
14
15
|
from rest_framework import serializers
|
|
15
16
|
|
|
@@ -387,7 +388,7 @@ class PythonPackageContentSerializer(core_serializers.SingleArtifactContentUploa
|
|
|
387
388
|
attestations = TypeAdapter(list[Attestation]).validate_json(value)
|
|
388
389
|
else:
|
|
389
390
|
attestations = TypeAdapter(list[Attestation]).validate_python(value)
|
|
390
|
-
except
|
|
391
|
+
except PydanticValidationError as e:
|
|
391
392
|
raise serializers.ValidationError(_("Invalid attestations: {}").format(e))
|
|
392
393
|
return attestations
|
|
393
394
|
|
|
@@ -654,7 +655,7 @@ class PackageProvenanceSerializer(core_serializers.NoArtifactContentUploadSerial
|
|
|
654
655
|
try:
|
|
655
656
|
provenance = Provenance.model_validate_json(data["file"].read())
|
|
656
657
|
data["provenance"] = provenance.model_dump(mode="json")
|
|
657
|
-
except
|
|
658
|
+
except PydanticValidationError as e:
|
|
658
659
|
raise serializers.ValidationError(
|
|
659
660
|
_("The uploaded provenance is not valid: {}").format(e)
|
|
660
661
|
)
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
import logging
|
|
3
3
|
from functools import partial
|
|
4
|
-
from
|
|
5
|
-
from urllib.parse import urljoin
|
|
4
|
+
from urllib.parse import urljoin, urlparse
|
|
6
5
|
|
|
7
6
|
from aiohttp import ClientError, ClientResponseError
|
|
8
7
|
from bandersnatch.configuration import BandersnatchConfig
|
|
@@ -12,9 +11,9 @@ from lxml.etree import LxmlError
|
|
|
12
11
|
from packaging.requirements import Requirement
|
|
13
12
|
from pypi_attestations import Provenance
|
|
14
13
|
from pypi_simple import IndexPage
|
|
15
|
-
from rest_framework import serializers
|
|
16
14
|
|
|
17
15
|
from pulpcore.plugin.download import HttpDownloader
|
|
16
|
+
from pulpcore.plugin.exceptions import SyncError
|
|
18
17
|
from pulpcore.plugin.models import Artifact, ProgressReport, Remote, Repository
|
|
19
18
|
from pulpcore.plugin.stages import (
|
|
20
19
|
DeclarativeArtifact,
|
|
@@ -23,6 +22,7 @@ from pulpcore.plugin.stages import (
|
|
|
23
22
|
Stage,
|
|
24
23
|
)
|
|
25
24
|
|
|
25
|
+
from pulp_python.app.exceptions import UnsupportedProtocolError
|
|
26
26
|
from pulp_python.app.models import (
|
|
27
27
|
PackageProvenance,
|
|
28
28
|
PythonPackageContent,
|
|
@@ -45,14 +45,14 @@ def sync(remote_pk, repository_pk, mirror):
|
|
|
45
45
|
mirror (boolean): True for mirror mode, False for additive mode.
|
|
46
46
|
|
|
47
47
|
Raises:
|
|
48
|
-
|
|
48
|
+
SyncError
|
|
49
49
|
|
|
50
50
|
"""
|
|
51
51
|
remote = PythonRemote.objects.get(pk=remote_pk)
|
|
52
52
|
repository = Repository.objects.get(pk=repository_pk)
|
|
53
53
|
|
|
54
54
|
if not remote.url:
|
|
55
|
-
raise
|
|
55
|
+
raise SyncError("A remote must have a url attribute to sync.")
|
|
56
56
|
|
|
57
57
|
first_stage = PythonBanderStage(remote)
|
|
58
58
|
DeclarativeVersion(first_stage, repository, mirror).create()
|
|
@@ -115,7 +115,8 @@ class PythonBanderStage(Stage):
|
|
|
115
115
|
url = self.remote.url.rstrip("/")
|
|
116
116
|
downloader = self.remote.get_downloader(url=url)
|
|
117
117
|
if not isinstance(downloader, HttpDownloader):
|
|
118
|
-
|
|
118
|
+
scheme = urlparse(url).scheme
|
|
119
|
+
raise UnsupportedProtocolError(scheme)
|
|
119
120
|
|
|
120
121
|
async with Master(url, allow_non_https=True) as master:
|
|
121
122
|
# Replace the session with the remote's downloader session
|
|
@@ -4,10 +4,13 @@ from datetime import datetime, timezone
|
|
|
4
4
|
from django.contrib.sessions.models import Session
|
|
5
5
|
from django.db import transaction
|
|
6
6
|
from pydantic import TypeAdapter
|
|
7
|
+
from pydantic import ValidationError as PydanticValidationError
|
|
8
|
+
from pypi_attestations import AttestationError
|
|
7
9
|
|
|
8
10
|
from pulpcore.plugin.models import Artifact, Content, ContentArtifact, CreatedResource
|
|
9
11
|
from pulpcore.plugin.util import get_current_authenticated_user, get_domain, get_prn
|
|
10
12
|
|
|
13
|
+
from pulp_python.app.exceptions import AttestationVerificationError, InvalidAttestationsError
|
|
11
14
|
from pulp_python.app.models import PackageProvenance, PythonPackageContent, PythonRepository
|
|
12
15
|
from pulp_python.app.provenance import (
|
|
13
16
|
AnyPublisher,
|
|
@@ -123,13 +126,19 @@ def create_provenance(package, attestations, domain):
|
|
|
123
126
|
Returns:
|
|
124
127
|
the newly created PackageProvenance
|
|
125
128
|
"""
|
|
126
|
-
|
|
129
|
+
try:
|
|
130
|
+
attestations = TypeAdapter(list[Attestation]).validate_python(attestations)
|
|
131
|
+
except PydanticValidationError as e:
|
|
132
|
+
raise InvalidAttestationsError(str(e))
|
|
127
133
|
|
|
128
134
|
user = get_current_authenticated_user()
|
|
129
135
|
publisher = AnyPublisher(kind="Pulp User", prn=get_prn(user))
|
|
130
136
|
att_bundle = AttestationBundle(publisher=publisher, attestations=attestations)
|
|
131
137
|
provenance = Provenance(attestation_bundles=[att_bundle])
|
|
132
|
-
|
|
138
|
+
try:
|
|
139
|
+
verify_provenance(package.filename, package.sha256, provenance)
|
|
140
|
+
except AttestationError as e:
|
|
141
|
+
raise AttestationVerificationError(str(e))
|
|
133
142
|
provenance_json = provenance.model_dump(mode="json")
|
|
134
143
|
|
|
135
144
|
prov_sha256 = PackageProvenance.calculate_sha256(provenance_json)
|
|
@@ -11,7 +11,7 @@ from datetime import timezone
|
|
|
11
11
|
import pkginfo
|
|
12
12
|
from aiohttp.client_exceptions import ClientError
|
|
13
13
|
from django.conf import settings
|
|
14
|
-
from django.db.models import
|
|
14
|
+
from django.db.models import F, FilteredRelation, Q
|
|
15
15
|
from django.db.utils import IntegrityError
|
|
16
16
|
from jinja2 import Template
|
|
17
17
|
from packaging.requirements import Requirement
|
|
@@ -20,7 +20,7 @@ from packaging.version import InvalidVersion, parse
|
|
|
20
20
|
from pypi_simple import ACCEPT_JSON_PREFERRED, ProjectPage
|
|
21
21
|
|
|
22
22
|
from pulpcore.plugin.exceptions import TimeoutException
|
|
23
|
-
from pulpcore.plugin.models import Artifact, Remote
|
|
23
|
+
from pulpcore.plugin.models import Artifact, Remote
|
|
24
24
|
from pulpcore.plugin.util import get_domain
|
|
25
25
|
|
|
26
26
|
log = logging.getLogger(__name__)
|
|
@@ -375,12 +375,16 @@ def python_content_to_json(
|
|
|
375
375
|
Returns None if version is specified but not found within content_query
|
|
376
376
|
"""
|
|
377
377
|
if repository_version:
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
378
|
+
content_query = content_query.annotate(
|
|
379
|
+
active_membership=FilteredRelation(
|
|
380
|
+
"version_memberships",
|
|
381
|
+
condition=Q(
|
|
382
|
+
version_memberships__repository=repository_version.repository,
|
|
383
|
+
version_memberships__version_removed=None,
|
|
384
|
+
),
|
|
385
|
+
),
|
|
386
|
+
repo_added_time=F("active_membership__pulp_created"),
|
|
387
|
+
)
|
|
384
388
|
full_metadata = {"last_serial": 0} # For now the serial field isn't supported by Pulp
|
|
385
389
|
latest_content = latest_content_version(content_query, version)
|
|
386
390
|
if not latest_content:
|
|
@@ -174,7 +174,10 @@ def test_domain_content_replication(
|
|
|
174
174
|
pulpcore_bindings.UpstreamPulpsApi, upstream_pulp_body, pulp_domain=replica_domain.name
|
|
175
175
|
)
|
|
176
176
|
# Run the replicate task and assert that all tasks successfully complete.
|
|
177
|
-
response = pulpcore_bindings.UpstreamPulpsApi.replicate(
|
|
177
|
+
response = pulpcore_bindings.UpstreamPulpsApi.replicate(
|
|
178
|
+
upstream_pulp.pulp_href,
|
|
179
|
+
upstream_pulp_replicate=pulpcore_bindings.module.UpstreamPulpReplicate(),
|
|
180
|
+
)
|
|
178
181
|
monitor_task_group(response.task_group)
|
|
179
182
|
|
|
180
183
|
counts = {}
|
|
@@ -198,7 +201,10 @@ def test_domain_content_replication(
|
|
|
198
201
|
body = {"remote": remote.pulp_href}
|
|
199
202
|
monitor_task(python_bindings.RepositoriesPythonApi.sync(repo.pulp_href, body).task)
|
|
200
203
|
|
|
201
|
-
response = pulpcore_bindings.UpstreamPulpsApi.replicate(
|
|
204
|
+
response = pulpcore_bindings.UpstreamPulpsApi.replicate(
|
|
205
|
+
upstream_pulp.pulp_href,
|
|
206
|
+
upstream_pulp_replicate=pulpcore_bindings.module.UpstreamPulpReplicate(),
|
|
207
|
+
)
|
|
202
208
|
monitor_task_group(response.task_group)
|
|
203
209
|
|
|
204
210
|
response = python_bindings.ContentPackagesApi.list(pulp_domain=replica_domain.name)
|
|
@@ -17,6 +17,7 @@ pulp_python.egg-info/entry_points.txt
|
|
|
17
17
|
pulp_python.egg-info/requires.txt
|
|
18
18
|
pulp_python.egg-info/top_level.txt
|
|
19
19
|
pulp_python/app/__init__.py
|
|
20
|
+
pulp_python/app/exceptions.py
|
|
20
21
|
pulp_python/app/global_access_conditions.py
|
|
21
22
|
pulp_python/app/modelresource.py
|
|
22
23
|
pulp_python/app/models.py
|
|
@@ -7,7 +7,7 @@ build-backend = 'setuptools.build_meta'
|
|
|
7
7
|
|
|
8
8
|
[project]
|
|
9
9
|
name = "pulp-python"
|
|
10
|
-
version = "3.
|
|
10
|
+
version = "3.31.0"
|
|
11
11
|
description = "pulp-python plugin for the Pulp Project"
|
|
12
12
|
readme = "README.md"
|
|
13
13
|
authors = [
|
|
@@ -79,7 +79,7 @@ ignore = [
|
|
|
79
79
|
[tool.bumpversion]
|
|
80
80
|
# This section is managed by the plugin template. Do not edit manually.
|
|
81
81
|
|
|
82
|
-
current_version = "3.
|
|
82
|
+
current_version = "3.31.0"
|
|
83
83
|
commit = false
|
|
84
84
|
tag = false
|
|
85
85
|
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_python-3.30.2 → pulp_python-3.31.0}/pulp_python/app/migrations/0003_new_sync_filters.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/app/migrations/0010_update_json_field.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/app/migrations/0013_add_rbac_permissions.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/app/migrations/0018_packageprovenance.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/app/migrations/0022_pythonblocklistentry.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
|
{pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/tests/functional/api/test_attestations.py
RENAMED
|
File without changes
|
{pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/tests/functional/api/test_auto_publish.py
RENAMED
|
File without changes
|
{pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/tests/functional/api/test_blocklist.py
RENAMED
|
File without changes
|
{pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/tests/functional/api/test_consume_content.py
RENAMED
|
File without changes
|
{pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/tests/functional/api/test_crud_content_unit.py
RENAMED
|
File without changes
|
{pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/tests/functional/api/test_crud_publications.py
RENAMED
|
File without changes
|
{pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/tests/functional/api/test_crud_remotes.py
RENAMED
|
File without changes
|
{pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/tests/functional/api/test_download_content.py
RENAMED
|
File without changes
|
{pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/tests/functional/api/test_export_import.py
RENAMED
|
File without changes
|
{pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/tests/functional/api/test_full_mirror.py
RENAMED
|
File without changes
|
{pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/tests/functional/api/test_pypi_apis.py
RENAMED
|
File without changes
|
{pulp_python-3.30.2 → pulp_python-3.31.0}/pulp_python/tests/functional/api/test_pypi_simple_api.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
|