pulp-python 3.20.0__tar.gz → 3.21.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.20.0 → pulp_python-3.21.0}/CHANGES.md +18 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/PKG-INFO +3 -3
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/app/__init__.py +1 -1
- pulp_python-3.21.0/pulp_python/app/migrations/0017_pythonpackagecontent_size.py +50 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/app/models.py +1 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/app/pypi/views.py +44 -46
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/app/serializers.py +10 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/app/tasks/__init__.py +1 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/app/tasks/sync.py +2 -1
- pulp_python-3.21.0/pulp_python/app/tasks/vulnerability_report.py +30 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/app/utils.py +19 -5
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/app/viewsets.py +30 -2
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/pytest_plugin.py +1 -1
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/tests/functional/api/test_full_mirror.py +30 -4
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/tests/functional/api/test_pypi_apis.py +5 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/tests/functional/api/test_pypi_simple_json_api.py +6 -2
- pulp_python-3.21.0/pulp_python/tests/functional/api/test_vulnerability_report.py +48 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/tests/functional/constants.py +5 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python.egg-info/PKG-INFO +3 -3
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python.egg-info/SOURCES.txt +3 -0
- pulp_python-3.21.0/pulp_python.egg-info/requires.txt +4 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pyproject.toml +4 -4
- pulp_python-3.20.0/pulp_python.egg-info/requires.txt +0 -4
- {pulp_python-3.20.0 → pulp_python-3.21.0}/COMMITMENT +0 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/COPYRIGHT +0 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/LICENSE +0 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/MANIFEST.in +0 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/README.md +0 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/functest_requirements.txt +0 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/__init__.py +0 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/app/global_access_conditions.py +0 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/app/management/__init__.py +0 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/app/management/commands/__init__.py +0 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/app/management/commands/repair-python-metadata.py +0 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/app/migrations/0001_initial.py +0 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/app/migrations/0001_squashed_0010_update_json_field.py +0 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/app/migrations/0002_pythonpackagecontent_python_version.py +0 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/app/migrations/0003_new_sync_filters.py +0 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/app/migrations/0004_DATA_swap_distribution_model.py +0 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/app/migrations/0005_pythonpackagecontent_sha256.py +0 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/app/migrations/0006_pythonrepository_autopublish.py +0 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/app/migrations/0007_pythonpackagecontent_mv-2-1.py +0 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/app/migrations/0008_pythonpackagecontent_unique_sha256.py +0 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/app/migrations/0009_pythondistribution_allow_uploads.py +0 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/app/migrations/0010_update_json_field.py +0 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/app/migrations/0011_alter_pythondistribution_distribution_ptr_and_more.py +0 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/app/migrations/0012_add_domain.py +0 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/app/migrations/0013_add_rbac_permissions.py +0 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/app/migrations/0014_pythonpackagecontent_dynamic_and_more.py +0 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/app/migrations/0015_alter_pythonpackagecontent_options.py +0 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/app/migrations/0016_pythonpackagecontent_metadata_sha256.py +0 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/app/migrations/__init__.py +0 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/app/modelresource.py +0 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/app/pypi/__init__.py +0 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/app/pypi/serializers.py +0 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/app/replica.py +0 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/app/settings.py +0 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/app/tasks/publish.py +0 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/app/tasks/repair.py +0 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/app/tasks/upload.py +0 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/app/urls.py +0 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/app/webserver_snippets/__init__.py +0 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/app/webserver_snippets/apache.conf +0 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/app/webserver_snippets/nginx.conf +0 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/tests/__init__.py +0 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/tests/functional/__init__.py +0 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/tests/functional/api/__init__.py +0 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/tests/functional/api/test_auto_publish.py +0 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/tests/functional/api/test_consume_content.py +0 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/tests/functional/api/test_crud_content_unit.py +0 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/tests/functional/api/test_crud_publications.py +0 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/tests/functional/api/test_crud_remotes.py +0 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/tests/functional/api/test_domains.py +0 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/tests/functional/api/test_download_content.py +0 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/tests/functional/api/test_export_import.py +0 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/tests/functional/api/test_rbac.py +0 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/tests/functional/api/test_repair.py +0 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/tests/functional/api/test_sync.py +0 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/tests/functional/api/test_upload.py +0 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/tests/functional/utils.py +0 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/tests/unit/__init__.py +0 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/tests/unit/test_models.py +0 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python.egg-info/dependency_links.txt +0 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python.egg-info/entry_points.txt +0 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python.egg-info/top_level.txt +0 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/setup.cfg +0 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/test_requirements.txt +0 -0
- {pulp_python-3.20.0 → pulp_python-3.21.0}/unittest_requirements.txt +0 -0
|
@@ -8,6 +8,24 @@
|
|
|
8
8
|
|
|
9
9
|
[//]: # (towncrier release notes start)
|
|
10
10
|
|
|
11
|
+
## 3.21.0 (2025-11-18) {: #3.21.0 }
|
|
12
|
+
|
|
13
|
+
#### Features {: #3.21.0-feature }
|
|
14
|
+
|
|
15
|
+
- Added ability to serve a specific repository version of a PyPI index.
|
|
16
|
+
[#982](https://github.com/pulp/pulp_python/issues/982)
|
|
17
|
+
- Implemented PEP 700 support, adding `versions`, `size` and `upload-time` to the Simple JSON API.
|
|
18
|
+
[#996](https://github.com/pulp/pulp_python/issues/996)
|
|
19
|
+
- Added the new /scan endpoint to the RepositoryVersion viewset to generate vulnerability reports.
|
|
20
|
+
[#1012](https://github.com/pulp/pulp_python/issues/1012)
|
|
21
|
+
|
|
22
|
+
#### Bugfixes {: #3.21.0-bugfix }
|
|
23
|
+
|
|
24
|
+
- Fixed pull-through caching not checking the repository if package was not present on remote.
|
|
25
|
+
[#1004](https://github.com/pulp/pulp_python/issues/1004)
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
11
29
|
## 3.20.0 (2025-11-07) {: #3.20.0 }
|
|
12
30
|
|
|
13
31
|
#### Features {: #3.20.0-feature }
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pulp-python
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.21.0
|
|
4
4
|
Summary: pulp-python plugin for the Pulp Project
|
|
5
5
|
Author-email: Pulp Team <pulp-list@redhat.com>
|
|
6
6
|
Project-URL: Homepage, https://pulpproject.org
|
|
@@ -20,9 +20,9 @@ Classifier: Programming Language :: Python :: 3.13
|
|
|
20
20
|
Requires-Python: >=3.11
|
|
21
21
|
Description-Content-Type: text/markdown
|
|
22
22
|
License-File: LICENSE
|
|
23
|
-
Requires-Dist: pulpcore<3.100,>=3.
|
|
23
|
+
Requires-Dist: pulpcore<3.100,>=3.85.3
|
|
24
24
|
Requires-Dist: pkginfo<1.13.0,>=1.12.0
|
|
25
|
-
Requires-Dist: bandersnatch<6.
|
|
25
|
+
Requires-Dist: bandersnatch<6.7,>=6.6.0
|
|
26
26
|
Requires-Dist: pypi-simple<2.0,>=1.5.0
|
|
27
27
|
Dynamic: license-file
|
|
28
28
|
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Generated by Django 4.2.26 on 2025-11-11 21:43
|
|
2
|
+
|
|
3
|
+
from django.db import migrations, models, transaction
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def add_size_to_current_models(apps, schema_editor):
|
|
7
|
+
"""Adds the size to current PythonPackageContent models."""
|
|
8
|
+
PythonPackageContent = apps.get_model("python", "PythonPackageContent")
|
|
9
|
+
RemoteArtifact = apps.get_model("core", "RemoteArtifact")
|
|
10
|
+
package_bulk = []
|
|
11
|
+
for python_package in PythonPackageContent.objects.only("pk", "size").iterator():
|
|
12
|
+
content_artifact = python_package.contentartifact_set.first()
|
|
13
|
+
if content_artifact.artifact:
|
|
14
|
+
artifact = content_artifact.artifact
|
|
15
|
+
else:
|
|
16
|
+
artifact = RemoteArtifact.objects.filter(content_artifact=content_artifact).first()
|
|
17
|
+
python_package.size = artifact.size or 0
|
|
18
|
+
package_bulk.append(python_package)
|
|
19
|
+
if len(package_bulk) == 100000:
|
|
20
|
+
with transaction.atomic():
|
|
21
|
+
PythonPackageContent.objects.bulk_update(
|
|
22
|
+
package_bulk,
|
|
23
|
+
[
|
|
24
|
+
"size",
|
|
25
|
+
],
|
|
26
|
+
)
|
|
27
|
+
package_bulk = []
|
|
28
|
+
with transaction.atomic():
|
|
29
|
+
PythonPackageContent.objects.bulk_update(
|
|
30
|
+
package_bulk,
|
|
31
|
+
[
|
|
32
|
+
"size",
|
|
33
|
+
],
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class Migration(migrations.Migration):
|
|
38
|
+
|
|
39
|
+
dependencies = [
|
|
40
|
+
("python", "0016_pythonpackagecontent_metadata_sha256"),
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
operations = [
|
|
44
|
+
migrations.AddField(
|
|
45
|
+
model_name="pythonpackagecontent",
|
|
46
|
+
name="size",
|
|
47
|
+
field=models.BigIntegerField(default=0),
|
|
48
|
+
),
|
|
49
|
+
migrations.RunPython(add_size_to_current_models, migrations.RunPython.noop, elidable=True),
|
|
50
|
+
]
|
|
@@ -193,6 +193,7 @@ class PythonPackageContent(Content):
|
|
|
193
193
|
python_version = models.TextField()
|
|
194
194
|
sha256 = models.CharField(db_index=True, max_length=64)
|
|
195
195
|
metadata_sha256 = models.CharField(max_length=64, null=True)
|
|
196
|
+
size = models.BigIntegerField(default=0)
|
|
196
197
|
# yanked and yanked_reason are not implemented because they are mutable
|
|
197
198
|
|
|
198
199
|
# From pulpcore
|
|
@@ -15,6 +15,7 @@ from django.db import transaction
|
|
|
15
15
|
from django.db.utils import DatabaseError
|
|
16
16
|
from django.http.response import (
|
|
17
17
|
Http404,
|
|
18
|
+
HttpResponseNotFound,
|
|
18
19
|
HttpResponseForbidden,
|
|
19
20
|
HttpResponseBadRequest,
|
|
20
21
|
StreamingHttpResponse,
|
|
@@ -104,10 +105,13 @@ class PyPIMixin:
|
|
|
104
105
|
"""Finds the repository version this distribution is serving."""
|
|
105
106
|
pub = distribution.publication
|
|
106
107
|
rep = distribution.repository
|
|
108
|
+
rep_version = distribution.repository_version
|
|
107
109
|
if pub:
|
|
108
110
|
return pub.repository_version or pub.repository.latest_version()
|
|
109
111
|
elif rep:
|
|
110
112
|
return rep.latest_version()
|
|
113
|
+
elif rep_version:
|
|
114
|
+
return rep_version
|
|
111
115
|
else:
|
|
112
116
|
raise Http404("No repository associated with this index")
|
|
113
117
|
|
|
@@ -287,7 +291,7 @@ class SimpleView(PackageUploadMixin, ViewSet):
|
|
|
287
291
|
kwargs = {"content_type": media_type, "headers": headers}
|
|
288
292
|
return StreamingHttpResponse(index_data, **kwargs)
|
|
289
293
|
|
|
290
|
-
def pull_through_package_simple(self, package, path, remote
|
|
294
|
+
def pull_through_package_simple(self, package, path, remote):
|
|
291
295
|
"""Gets the package's simple page from remote."""
|
|
292
296
|
|
|
293
297
|
def parse_package(release_package):
|
|
@@ -301,11 +305,14 @@ class SimpleView(PackageUploadMixin, ViewSet):
|
|
|
301
305
|
"sha256": release_package.digests.get("sha256", ""),
|
|
302
306
|
"requires_python": release_package.requires_python,
|
|
303
307
|
"metadata_sha256": (release_package.metadata_digests or {}).get("sha256"),
|
|
308
|
+
"size": release_package.size,
|
|
309
|
+
"upload_time": release_package.upload_time,
|
|
310
|
+
"version": release_package.version,
|
|
304
311
|
}
|
|
305
312
|
|
|
306
313
|
rfilter = get_remote_package_filter(remote)
|
|
307
314
|
if not rfilter.filter_project(package):
|
|
308
|
-
|
|
315
|
+
return {}
|
|
309
316
|
|
|
310
317
|
url = remote.get_remote_artifact_url(f"simple/{package}/")
|
|
311
318
|
remote.headers = remote.headers or []
|
|
@@ -313,27 +320,19 @@ class SimpleView(PackageUploadMixin, ViewSet):
|
|
|
313
320
|
downloader = remote.get_downloader(url=url, max_retries=1)
|
|
314
321
|
try:
|
|
315
322
|
d = downloader.fetch()
|
|
316
|
-
except ClientError:
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
return HttpResponse(f"{remote.url} timed out while fetching {package}.", status=504)
|
|
323
|
+
except (ClientError, TimeoutException):
|
|
324
|
+
log.info(f"Failed to fetch {package} simple page from {remote.url}")
|
|
325
|
+
return {}
|
|
320
326
|
|
|
321
327
|
if d.headers["content-type"] == PYPI_SIMPLE_V1_JSON:
|
|
322
328
|
page = ProjectPage.from_json_data(json.load(open(d.path, "rb")), base_url=url)
|
|
323
329
|
else:
|
|
324
330
|
page = ProjectPage.from_html(package, open(d.path, "rb").read(), base_url=url)
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
if media_type == PYPI_SIMPLE_V1_JSON:
|
|
331
|
-
detail_data = write_simple_detail_json(package, packages)
|
|
332
|
-
return Response(detail_data, headers=headers)
|
|
333
|
-
else:
|
|
334
|
-
detail_data = write_simple_detail(package, packages)
|
|
335
|
-
kwargs = {"content_type": media_type, "headers": headers}
|
|
336
|
-
return HttpResponse(detail_data, **kwargs)
|
|
331
|
+
return {
|
|
332
|
+
p.filename: parse_package(p)
|
|
333
|
+
for p in page.packages
|
|
334
|
+
if rfilter.filter_release(package, p.version)
|
|
335
|
+
}
|
|
337
336
|
|
|
338
337
|
@extend_schema(operation_id="pypi_simple_package_read", summary="Get package simple page")
|
|
339
338
|
def retrieve(self, request, path, package):
|
|
@@ -343,44 +342,43 @@ class SimpleView(PackageUploadMixin, ViewSet):
|
|
|
343
342
|
repo_ver, content = self.get_rvc()
|
|
344
343
|
# Should I redirect if the normalized name is different?
|
|
345
344
|
normalized = canonicalize_name(package)
|
|
345
|
+
releases = {}
|
|
346
346
|
if self.distribution.remote:
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
)
|
|
350
|
-
if self.should_redirect(repo_version=repo_ver):
|
|
347
|
+
releases = self.pull_through_package_simple(normalized, path, self.distribution.remote)
|
|
348
|
+
elif self.should_redirect(repo_version=repo_ver):
|
|
351
349
|
return redirect(urljoin(self.base_content_url, f"{path}/simple/{normalized}/"))
|
|
352
|
-
|
|
353
|
-
content.filter(name__normalize=normalized)
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
"metadata_sha256": metadata_sha256,
|
|
370
|
-
"requires_python": requires_python,
|
|
350
|
+
if content:
|
|
351
|
+
packages = content.filter(name__normalize=normalized).values(
|
|
352
|
+
"filename",
|
|
353
|
+
"sha256",
|
|
354
|
+
"metadata_sha256",
|
|
355
|
+
"requires_python",
|
|
356
|
+
"size",
|
|
357
|
+
"pulp_created",
|
|
358
|
+
"version",
|
|
359
|
+
)
|
|
360
|
+
local_releases = {
|
|
361
|
+
p["filename"]: {
|
|
362
|
+
**p,
|
|
363
|
+
"url": urljoin(self.base_content_url, f"{path}/{p['filename']}"),
|
|
364
|
+
"upload_time": p["pulp_created"],
|
|
365
|
+
}
|
|
366
|
+
for p in packages
|
|
371
367
|
}
|
|
372
|
-
|
|
373
|
-
|
|
368
|
+
releases.update(local_releases)
|
|
369
|
+
if not releases:
|
|
370
|
+
return HttpResponseNotFound(f"{normalized} does not exist.")
|
|
371
|
+
|
|
374
372
|
media_type = request.accepted_renderer.media_type
|
|
375
373
|
headers = {"X-PyPI-Last-Serial": str(PYPI_SERIAL_CONSTANT)}
|
|
376
374
|
|
|
377
375
|
if media_type == PYPI_SIMPLE_V1_JSON:
|
|
378
|
-
detail_data = write_simple_detail_json(
|
|
376
|
+
detail_data = write_simple_detail_json(normalized, releases.values())
|
|
379
377
|
return Response(detail_data, headers=headers)
|
|
380
378
|
else:
|
|
381
|
-
detail_data = write_simple_detail(
|
|
379
|
+
detail_data = write_simple_detail(normalized, releases.values())
|
|
382
380
|
kwargs = {"content_type": media_type, "headers": headers}
|
|
383
|
-
return
|
|
381
|
+
return HttpResponse(detail_data, **kwargs)
|
|
384
382
|
|
|
385
383
|
@extend_schema(
|
|
386
384
|
request=PackageUploadSerializer,
|
|
@@ -53,6 +53,9 @@ class PythonDistributionSerializer(core_serializers.DistributionSerializer):
|
|
|
53
53
|
queryset=core_models.Publication.objects.exclude(complete=False),
|
|
54
54
|
allow_null=True,
|
|
55
55
|
)
|
|
56
|
+
repository_version = core_serializers.RepositoryVersionRelatedField(
|
|
57
|
+
required=False, help_text=_("RepositoryVersion to be served."), allow_null=True
|
|
58
|
+
)
|
|
56
59
|
base_url = serializers.SerializerMethodField(read_only=True)
|
|
57
60
|
allow_uploads = serializers.BooleanField(
|
|
58
61
|
default=True, help_text=_("Allow packages to be uploaded to this index.")
|
|
@@ -74,6 +77,7 @@ class PythonDistributionSerializer(core_serializers.DistributionSerializer):
|
|
|
74
77
|
class Meta:
|
|
75
78
|
fields = core_serializers.DistributionSerializer.Meta.fields + (
|
|
76
79
|
"publication",
|
|
80
|
+
"repository_version",
|
|
77
81
|
"allow_uploads",
|
|
78
82
|
"remote",
|
|
79
83
|
)
|
|
@@ -277,6 +281,10 @@ class PythonPackageContentSerializer(core_serializers.SingleArtifactContentUploa
|
|
|
277
281
|
),
|
|
278
282
|
read_only=True,
|
|
279
283
|
)
|
|
284
|
+
size = serializers.IntegerField(
|
|
285
|
+
help_text=_("The size of the package in bytes."),
|
|
286
|
+
read_only=True,
|
|
287
|
+
)
|
|
280
288
|
sha256 = serializers.CharField(
|
|
281
289
|
default="",
|
|
282
290
|
help_text=_("The SHA256 digest of this package."),
|
|
@@ -368,6 +376,7 @@ class PythonPackageContentSerializer(core_serializers.SingleArtifactContentUploa
|
|
|
368
376
|
"filename",
|
|
369
377
|
"packagetype",
|
|
370
378
|
"python_version",
|
|
379
|
+
"size",
|
|
371
380
|
"sha256",
|
|
372
381
|
"metadata_sha256",
|
|
373
382
|
)
|
|
@@ -421,6 +430,7 @@ class PythonPackageContentUploadSerializer(PythonPackageContentSerializer):
|
|
|
421
430
|
data["artifact"] = artifact
|
|
422
431
|
data["sha256"] = artifact.sha256
|
|
423
432
|
data["relative_path"] = filename
|
|
433
|
+
data["size"] = artifact.size
|
|
424
434
|
data.update(parse_project_metadata(vars(metadata)))
|
|
425
435
|
# Overwrite filename from metadata
|
|
426
436
|
data["filename"] = filename
|
|
@@ -59,9 +59,10 @@ def sync(remote_pk, repository_pk, mirror):
|
|
|
59
59
|
|
|
60
60
|
def create_bandersnatch_config(remote):
|
|
61
61
|
"""Modifies the global Bandersnatch config state for this sync"""
|
|
62
|
-
config = BandersnatchConfig()
|
|
62
|
+
config = BandersnatchConfig()
|
|
63
63
|
config["mirror"]["master"] = remote.url
|
|
64
64
|
config["mirror"]["workers"] = str(remote.download_concurrency)
|
|
65
|
+
config["mirror"]["allow_non_https"] = "true"
|
|
65
66
|
if not config.has_section("plugins"):
|
|
66
67
|
config.add_section("plugins")
|
|
67
68
|
config["plugins"]["enabled"] = "blocklist_release\n"
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
from pulpcore.plugin.models import RepositoryVersion
|
|
2
|
+
from pulpcore.plugin.sync import sync_to_async_iterable
|
|
3
|
+
|
|
4
|
+
from pulp_python.app.models import PythonPackageContent
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
async def get_repo_version_content(repo_version_pk: str):
|
|
8
|
+
"""
|
|
9
|
+
Retrieve Python package content from a repository version for vulnerability scanning.
|
|
10
|
+
"""
|
|
11
|
+
repo_version = await RepositoryVersion.objects.aget(pk=repo_version_pk)
|
|
12
|
+
content_units = PythonPackageContent.objects.filter(pk__in=repo_version.content).only(
|
|
13
|
+
"name", "version"
|
|
14
|
+
)
|
|
15
|
+
ecosystem = "PyPI"
|
|
16
|
+
async for content in sync_to_async_iterable(content_units):
|
|
17
|
+
repo_content_osv_data = _build_osv_data(content.name, ecosystem, content.version)
|
|
18
|
+
repo_content_osv_data["repo_version"] = repo_version
|
|
19
|
+
repo_content_osv_data["content"] = content
|
|
20
|
+
yield repo_content_osv_data
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _build_osv_data(name, ecosystem, version=None):
|
|
24
|
+
"""
|
|
25
|
+
Build an OSV data structure for vulnerability queries.
|
|
26
|
+
"""
|
|
27
|
+
osv_data = {"package": {"name": name, "ecosystem": ecosystem}}
|
|
28
|
+
if version:
|
|
29
|
+
osv_data["version"] = version
|
|
30
|
+
return osv_data
|
|
@@ -7,6 +7,7 @@ import zipfile
|
|
|
7
7
|
import json
|
|
8
8
|
from collections import defaultdict
|
|
9
9
|
from django.conf import settings
|
|
10
|
+
from django.utils import timezone
|
|
10
11
|
from jinja2 import Template
|
|
11
12
|
from packaging.utils import canonicalize_name
|
|
12
13
|
from packaging.requirements import Requirement
|
|
@@ -18,7 +19,7 @@ PYPI_LAST_SERIAL = "X-PYPI-LAST-SERIAL"
|
|
|
18
19
|
"""TODO This serial constant is temporary until Python repositories implements serials"""
|
|
19
20
|
PYPI_SERIAL_CONSTANT = 1000000000
|
|
20
21
|
|
|
21
|
-
SIMPLE_API_VERSION = "1.
|
|
22
|
+
SIMPLE_API_VERSION = "1.1"
|
|
22
23
|
|
|
23
24
|
simple_index_template = """<!DOCTYPE html>
|
|
24
25
|
<html>
|
|
@@ -161,6 +162,7 @@ def parse_metadata(project, version, distribution):
|
|
|
161
162
|
package["sha256"] = distribution.get("digests", {}).get("sha256") or ""
|
|
162
163
|
package["python_version"] = distribution.get("python_version") or ""
|
|
163
164
|
package["requires_python"] = distribution.get("requires_python") or ""
|
|
165
|
+
package["size"] = distribution.get("size") or 0
|
|
164
166
|
|
|
165
167
|
return package
|
|
166
168
|
|
|
@@ -223,6 +225,7 @@ def artifact_to_python_content_data(filename, artifact, domain=None):
|
|
|
223
225
|
metadata = get_project_metadata_from_file(temp_file.name)
|
|
224
226
|
data = parse_project_metadata(vars(metadata))
|
|
225
227
|
data["sha256"] = artifact.sha256
|
|
228
|
+
data["size"] = artifact.size
|
|
226
229
|
data["filename"] = filename
|
|
227
230
|
data["pulp_domain"] = domain or artifact.pulp_domain
|
|
228
231
|
data["_pulp_domain"] = data["pulp_domain"]
|
|
@@ -403,7 +406,6 @@ def python_content_to_download_info(content, base_path, domain=None):
|
|
|
403
406
|
components.insert(2, domain.name)
|
|
404
407
|
url = "/".join(components)
|
|
405
408
|
md5 = artifact.md5 if artifact and artifact.md5 else ""
|
|
406
|
-
size = artifact.size if artifact and artifact.size else 0
|
|
407
409
|
return {
|
|
408
410
|
"comment_text": "",
|
|
409
411
|
"digests": {"md5": md5, "sha256": content.sha256},
|
|
@@ -414,7 +416,7 @@ def python_content_to_download_info(content, base_path, domain=None):
|
|
|
414
416
|
"packagetype": content.packagetype,
|
|
415
417
|
"python_version": content.python_version,
|
|
416
418
|
"requires_python": content.requires_python or None,
|
|
417
|
-
"size": size,
|
|
419
|
+
"size": content.size,
|
|
418
420
|
"upload_time": str(content.pulp_created),
|
|
419
421
|
"upload_time_iso_8601": str(content.pulp_created.isoformat()),
|
|
420
422
|
"url": url,
|
|
@@ -471,20 +473,32 @@ def write_simple_detail_json(project_name, project_packages):
|
|
|
471
473
|
{"sha256": package["metadata_sha256"]} if package["metadata_sha256"] else False
|
|
472
474
|
),
|
|
473
475
|
# yanked and yanked_reason are not implemented because they are mutable
|
|
476
|
+
# (v1.1, PEP 700)
|
|
477
|
+
"size": package["size"],
|
|
478
|
+
"upload-time": format_upload_time(package["upload_time"]),
|
|
474
479
|
# TODO in the future:
|
|
475
|
-
# size, upload-time (v1.1, PEP 700)
|
|
476
480
|
# core-metadata (PEP 7.14)
|
|
477
481
|
# provenance (v1.3, PEP 740)
|
|
478
482
|
}
|
|
479
483
|
for package in project_packages
|
|
480
484
|
],
|
|
485
|
+
# (v1.1, PEP 700)
|
|
486
|
+
"versions": sorted(set(package["version"] for package in project_packages)),
|
|
481
487
|
# TODO in the future:
|
|
482
|
-
# versions (v1.1, PEP 700)
|
|
483
488
|
# alternate-locations (v1.2, PEP 708)
|
|
484
489
|
# project-status (v1.4, PEP 792 - pypi and docs differ)
|
|
485
490
|
}
|
|
486
491
|
|
|
487
492
|
|
|
493
|
+
def format_upload_time(upload_time):
|
|
494
|
+
"""Formats the upload time to be in Zulu time. UTC with Z suffix"""
|
|
495
|
+
if upload_time:
|
|
496
|
+
if upload_time.tzinfo:
|
|
497
|
+
dt = upload_time.astimezone(timezone.utc)
|
|
498
|
+
return dt.isoformat().replace("+00:00", "Z")
|
|
499
|
+
return None
|
|
500
|
+
|
|
501
|
+
|
|
488
502
|
class PackageIncludeFilter:
|
|
489
503
|
"""A special class to help filter Package's based on a remote's include/exclude"""
|
|
490
504
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from bandersnatch.configuration import BandersnatchConfig
|
|
2
2
|
from django.db import transaction
|
|
3
3
|
from drf_spectacular.utils import extend_schema
|
|
4
|
+
from pathlib import Path
|
|
4
5
|
from rest_framework import status
|
|
5
6
|
from rest_framework.decorators import action
|
|
6
7
|
from rest_framework.response import Response
|
|
@@ -12,7 +13,7 @@ from pulpcore.plugin.serializers import (
|
|
|
12
13
|
AsyncOperationResponseSerializer,
|
|
13
14
|
RepositorySyncURLSerializer,
|
|
14
15
|
)
|
|
15
|
-
from pulpcore.plugin.tasking import dispatch
|
|
16
|
+
from pulpcore.plugin.tasking import check_content, dispatch
|
|
16
17
|
|
|
17
18
|
from pulp_python.app import models as python_models
|
|
18
19
|
from pulp_python.app import serializers as python_serializers
|
|
@@ -205,9 +206,36 @@ class PythonRepositoryVersionViewSet(core_viewsets.RepositoryVersionViewSet):
|
|
|
205
206
|
"has_repository_model_or_domain_or_obj_perms:python.view_pythonrepository",
|
|
206
207
|
],
|
|
207
208
|
},
|
|
209
|
+
{
|
|
210
|
+
"action": ["scan"],
|
|
211
|
+
"principal": "authenticated",
|
|
212
|
+
"effect": "allow",
|
|
213
|
+
"condition": [
|
|
214
|
+
"has_repository_model_or_domain_or_obj_perms:python.view_pythonrepository",
|
|
215
|
+
],
|
|
216
|
+
},
|
|
208
217
|
],
|
|
209
218
|
}
|
|
210
219
|
|
|
220
|
+
@extend_schema(
|
|
221
|
+
summary="Generate vulnerability report", responses={202: AsyncOperationResponseSerializer}
|
|
222
|
+
)
|
|
223
|
+
@action(detail=True, methods=["post"], serializer_class=None)
|
|
224
|
+
def scan(self, request, repository_pk, **kwargs):
|
|
225
|
+
"""
|
|
226
|
+
Scan a repository version for vulnerabilities.
|
|
227
|
+
"""
|
|
228
|
+
repository_version = self.get_object()
|
|
229
|
+
func = (
|
|
230
|
+
f"{tasks.get_repo_version_content.__module__}.{tasks.get_repo_version_content.__name__}"
|
|
231
|
+
)
|
|
232
|
+
task = dispatch(
|
|
233
|
+
check_content,
|
|
234
|
+
shared_resources=[repository_version.repository],
|
|
235
|
+
args=[func, [repository_version.pk]],
|
|
236
|
+
)
|
|
237
|
+
return core_viewsets.OperationPostponedResponse(task, request)
|
|
238
|
+
|
|
211
239
|
|
|
212
240
|
class PythonDistributionViewSet(core_viewsets.DistributionViewSet, core_viewsets.RolesMixin):
|
|
213
241
|
"""
|
|
@@ -496,7 +524,7 @@ class PythonRemoteViewSet(core_viewsets.RemoteViewSet, core_viewsets.RolesMixin)
|
|
|
496
524
|
bander_config_file = serializer.validated_data.get("config")
|
|
497
525
|
name = serializer.validated_data.get("name")
|
|
498
526
|
policy = serializer.validated_data.get("policy")
|
|
499
|
-
bander_config = BandersnatchConfig(bander_config_file.file.name)
|
|
527
|
+
bander_config = BandersnatchConfig(Path(bander_config_file.file.name))
|
|
500
528
|
data = {
|
|
501
529
|
"name": name,
|
|
502
530
|
"policy": policy,
|
|
@@ -73,7 +73,7 @@ def python_distribution_factory(python_bindings, gen_object_with_cleanup):
|
|
|
73
73
|
ver_href = f"{repo_href}versions/{version}/"
|
|
74
74
|
else:
|
|
75
75
|
ver_href = get_href(version)
|
|
76
|
-
body
|
|
76
|
+
body["repository_version"] = ver_href
|
|
77
77
|
else:
|
|
78
78
|
body["repository"] = repo_href
|
|
79
79
|
kwargs = {}
|
{pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/tests/functional/api/test_full_mirror.py
RENAMED
|
@@ -84,7 +84,7 @@ def test_pull_through_filter(python_remote_factory, python_distribution_factory)
|
|
|
84
84
|
|
|
85
85
|
r = requests.get(f"{distro.base_url}simple/pulpcore/")
|
|
86
86
|
assert r.status_code == 404
|
|
87
|
-
assert r.text == "
|
|
87
|
+
assert r.text == "pulpcore does not exist."
|
|
88
88
|
|
|
89
89
|
r = requests.get(f"{distro.base_url}simple/shelf-reader/")
|
|
90
90
|
assert r.status_code == 200
|
|
@@ -104,11 +104,11 @@ def test_pull_through_filter(python_remote_factory, python_distribution_factory)
|
|
|
104
104
|
|
|
105
105
|
r = requests.get(f"{distro.base_url}simple/django/")
|
|
106
106
|
assert r.status_code == 404
|
|
107
|
-
assert r.text == "
|
|
107
|
+
assert r.text == "django does not exist."
|
|
108
108
|
|
|
109
109
|
r = requests.get(f"{distro.base_url}simple/pulpcore/")
|
|
110
|
-
assert r.status_code ==
|
|
111
|
-
assert r.text ==
|
|
110
|
+
assert r.status_code == 404
|
|
111
|
+
assert r.text == "pulpcore does not exist."
|
|
112
112
|
|
|
113
113
|
r = requests.get(f"{distro.base_url}simple/shelf-reader/")
|
|
114
114
|
assert r.status_code == 200
|
|
@@ -156,3 +156,29 @@ def test_pull_through_with_repo(
|
|
|
156
156
|
assert r.status_code == 200
|
|
157
157
|
tasks = pulpcore_bindings.TasksApi.list(reserved_resources=repo.prn)
|
|
158
158
|
assert tasks.count == 3
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
@pytest.mark.parallel
|
|
162
|
+
def test_pull_through_local_only(
|
|
163
|
+
python_remote_factory, python_distribution_factory, python_repo_with_sync
|
|
164
|
+
):
|
|
165
|
+
"""Tests that pull-through checks the repository if the package is not present on the remote."""
|
|
166
|
+
remote = python_remote_factory(url=PYPI_URL, includes=["pulpcore"])
|
|
167
|
+
repo = python_repo_with_sync(remote=remote)
|
|
168
|
+
remote2 = python_remote_factory(includes=[]) # Fixtures does not have pulpcore
|
|
169
|
+
distro = python_distribution_factory(repository=repo.pulp_href, remote=remote2.pulp_href)
|
|
170
|
+
|
|
171
|
+
url = f"{distro.base_url}simple/pulpcore/"
|
|
172
|
+
r = requests.get(url)
|
|
173
|
+
assert r.status_code == 200
|
|
174
|
+
assert "?redirect=" not in r.text
|
|
175
|
+
|
|
176
|
+
url = f"{distro.base_url}simple/shelf-reader/"
|
|
177
|
+
r = requests.get(url)
|
|
178
|
+
assert r.status_code == 200
|
|
179
|
+
assert "?redirect=" in r.text
|
|
180
|
+
|
|
181
|
+
url = f"{distro.base_url}simple/pulp_python/"
|
|
182
|
+
r = requests.get(url)
|
|
183
|
+
assert r.status_code == 404
|
|
184
|
+
assert r.text == "pulp-python does not exist."
|
{pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/tests/functional/api/test_pypi_apis.py
RENAMED
|
@@ -267,6 +267,11 @@ def test_pypi_json(python_remote_factory, python_repo_with_sync, python_distribu
|
|
|
267
267
|
distro = python_distribution_factory(repository=repo)
|
|
268
268
|
response = requests.get(urljoin(distro.base_url, "pypi/shelf-reader/json"))
|
|
269
269
|
assert_pypi_json(response.json())
|
|
270
|
+
# Test serving a repository version
|
|
271
|
+
distro = python_distribution_factory(repository=repo, version="1")
|
|
272
|
+
assert distro.repository is None
|
|
273
|
+
response = requests.get(urljoin(distro.base_url, "pypi/shelf-reader/json"))
|
|
274
|
+
assert_pypi_json(response.json())
|
|
270
275
|
|
|
271
276
|
|
|
272
277
|
@pytest.mark.parallel
|
|
@@ -11,7 +11,7 @@ from pulp_python.tests.functional.constants import (
|
|
|
11
11
|
PYTHON_WHEEL_URL,
|
|
12
12
|
)
|
|
13
13
|
|
|
14
|
-
API_VERSION = "1.
|
|
14
|
+
API_VERSION = "1.1"
|
|
15
15
|
PYPI_SERIAL_CONSTANT = 1000000000
|
|
16
16
|
|
|
17
17
|
PYPI_TEXT_HTML = "text/html"
|
|
@@ -69,6 +69,7 @@ def test_simple_json_detail_api(
|
|
|
69
69
|
assert data["meta"] == {"api-version": API_VERSION, "_last-serial": PYPI_SERIAL_CONSTANT}
|
|
70
70
|
assert data["name"] == "shelf-reader"
|
|
71
71
|
assert data["files"]
|
|
72
|
+
assert data["versions"] == ["0.1"]
|
|
72
73
|
|
|
73
74
|
# Check data of a wheel
|
|
74
75
|
file_whl = next(
|
|
@@ -83,7 +84,8 @@ def test_simple_json_detail_api(
|
|
|
83
84
|
assert file_whl["data-dist-info-metadata"] == {
|
|
84
85
|
"sha256": "ed333f0db05d77e933a157b7225b403ada9a2f93318d77b41b662eba78bac350"
|
|
85
86
|
}
|
|
86
|
-
|
|
87
|
+
assert file_whl["size"] == 22455
|
|
88
|
+
assert file_whl["upload-time"] is not None
|
|
87
89
|
# Check data of a tarball
|
|
88
90
|
file_tar = next((i for i in data["files"] if i["filename"] == "shelf-reader-0.1.tar.gz"), None)
|
|
89
91
|
assert file_tar is not None, "tar file not found"
|
|
@@ -93,6 +95,8 @@ def test_simple_json_detail_api(
|
|
|
93
95
|
}
|
|
94
96
|
assert file_tar["requires-python"] is None
|
|
95
97
|
assert file_tar["data-dist-info-metadata"] is False
|
|
98
|
+
assert file_tar["size"] == 19097
|
|
99
|
+
assert file_tar["upload-time"] is not None
|
|
96
100
|
|
|
97
101
|
|
|
98
102
|
@pytest.mark.parallel
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
|
|
3
|
+
from pulp_python.tests.functional.constants import (
|
|
4
|
+
PYPI_URL,
|
|
5
|
+
VULNERABILITY_REPORT_TEST_PACKAGE_NAME,
|
|
6
|
+
VULNERABILITY_REPORT_TEST_PACKAGES,
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@pytest.mark.parallel
|
|
11
|
+
def test_vulnerability_report(
|
|
12
|
+
pulpcore_bindings, python_bindings, python_repo, python_remote_factory, monitor_task
|
|
13
|
+
):
|
|
14
|
+
|
|
15
|
+
# Sync the test repository.
|
|
16
|
+
remote = python_remote_factory(url=PYPI_URL, includes=VULNERABILITY_REPORT_TEST_PACKAGES)
|
|
17
|
+
sync_data = dict(remote=remote.pulp_href)
|
|
18
|
+
response = python_bindings.RepositoriesPythonApi.sync(python_repo.pulp_href, sync_data)
|
|
19
|
+
monitor_task(response.task)
|
|
20
|
+
|
|
21
|
+
# get repo latest version
|
|
22
|
+
repo = python_bindings.RepositoriesPythonApi.read(python_repo.pulp_href)
|
|
23
|
+
latest_version_href = repo.latest_version_href
|
|
24
|
+
|
|
25
|
+
# scan
|
|
26
|
+
response = python_bindings.RepositoriesPythonVersionsApi.scan(
|
|
27
|
+
python_python_repository_version_href=latest_version_href
|
|
28
|
+
)
|
|
29
|
+
monitor_task(response.task)
|
|
30
|
+
|
|
31
|
+
# checks
|
|
32
|
+
vulns_list = pulpcore_bindings.VulnReportApi.list()
|
|
33
|
+
assert len(vulns_list.results) > 0
|
|
34
|
+
for results in vulns_list.results:
|
|
35
|
+
assert len(results.vulns) > 0
|
|
36
|
+
for vuln in results.vulns:
|
|
37
|
+
assert VULNERABILITY_REPORT_TEST_PACKAGE_NAME.lower() in (
|
|
38
|
+
affected["package"]["name"] for affected in vuln["affected"]
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
repo_version = python_bindings.RepositoriesPythonVersionsApi.read(latest_version_href)
|
|
42
|
+
assert repo_version.vuln_report is not None
|
|
43
|
+
|
|
44
|
+
python_packages = python_bindings.ContentPackagesApi.list(
|
|
45
|
+
name=VULNERABILITY_REPORT_TEST_PACKAGE_NAME, repository_version=latest_version_href
|
|
46
|
+
)
|
|
47
|
+
for content in python_packages.results:
|
|
48
|
+
assert content.vuln_report is not None
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pulp-python
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.21.0
|
|
4
4
|
Summary: pulp-python plugin for the Pulp Project
|
|
5
5
|
Author-email: Pulp Team <pulp-list@redhat.com>
|
|
6
6
|
Project-URL: Homepage, https://pulpproject.org
|
|
@@ -20,9 +20,9 @@ Classifier: Programming Language :: Python :: 3.13
|
|
|
20
20
|
Requires-Python: >=3.11
|
|
21
21
|
Description-Content-Type: text/markdown
|
|
22
22
|
License-File: LICENSE
|
|
23
|
-
Requires-Dist: pulpcore<3.100,>=3.
|
|
23
|
+
Requires-Dist: pulpcore<3.100,>=3.85.3
|
|
24
24
|
Requires-Dist: pkginfo<1.13.0,>=1.12.0
|
|
25
|
-
Requires-Dist: bandersnatch<6.
|
|
25
|
+
Requires-Dist: bandersnatch<6.7,>=6.6.0
|
|
26
26
|
Requires-Dist: pypi-simple<2.0,>=1.5.0
|
|
27
27
|
Dynamic: license-file
|
|
28
28
|
|
|
@@ -46,6 +46,7 @@ pulp_python/app/migrations/0013_add_rbac_permissions.py
|
|
|
46
46
|
pulp_python/app/migrations/0014_pythonpackagecontent_dynamic_and_more.py
|
|
47
47
|
pulp_python/app/migrations/0015_alter_pythonpackagecontent_options.py
|
|
48
48
|
pulp_python/app/migrations/0016_pythonpackagecontent_metadata_sha256.py
|
|
49
|
+
pulp_python/app/migrations/0017_pythonpackagecontent_size.py
|
|
49
50
|
pulp_python/app/migrations/__init__.py
|
|
50
51
|
pulp_python/app/pypi/__init__.py
|
|
51
52
|
pulp_python/app/pypi/serializers.py
|
|
@@ -55,6 +56,7 @@ pulp_python/app/tasks/publish.py
|
|
|
55
56
|
pulp_python/app/tasks/repair.py
|
|
56
57
|
pulp_python/app/tasks/sync.py
|
|
57
58
|
pulp_python/app/tasks/upload.py
|
|
59
|
+
pulp_python/app/tasks/vulnerability_report.py
|
|
58
60
|
pulp_python/app/webserver_snippets/__init__.py
|
|
59
61
|
pulp_python/app/webserver_snippets/apache.conf
|
|
60
62
|
pulp_python/app/webserver_snippets/nginx.conf
|
|
@@ -78,5 +80,6 @@ pulp_python/tests/functional/api/test_rbac.py
|
|
|
78
80
|
pulp_python/tests/functional/api/test_repair.py
|
|
79
81
|
pulp_python/tests/functional/api/test_sync.py
|
|
80
82
|
pulp_python/tests/functional/api/test_upload.py
|
|
83
|
+
pulp_python/tests/functional/api/test_vulnerability_report.py
|
|
81
84
|
pulp_python/tests/unit/__init__.py
|
|
82
85
|
pulp_python/tests/unit/test_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.21.0"
|
|
11
11
|
description = "pulp-python plugin for the Pulp Project"
|
|
12
12
|
readme = "README.md"
|
|
13
13
|
authors = [
|
|
@@ -26,9 +26,9 @@ classifiers=[
|
|
|
26
26
|
]
|
|
27
27
|
requires-python = ">=3.11"
|
|
28
28
|
dependencies = [
|
|
29
|
-
"pulpcore>=3.
|
|
29
|
+
"pulpcore>=3.85.3,<3.100",
|
|
30
30
|
"pkginfo>=1.12.0,<1.13.0",
|
|
31
|
-
"bandersnatch>=6.
|
|
31
|
+
"bandersnatch>=6.6.0,<6.7",
|
|
32
32
|
"pypi-simple>=1.5.0,<2.0",
|
|
33
33
|
]
|
|
34
34
|
|
|
@@ -76,7 +76,7 @@ ignore = [
|
|
|
76
76
|
[tool.bumpversion]
|
|
77
77
|
# This section is managed by the plugin template. Do not edit manually.
|
|
78
78
|
|
|
79
|
-
current_version = "3.
|
|
79
|
+
current_version = "3.21.0"
|
|
80
80
|
commit = false
|
|
81
81
|
tag = false
|
|
82
82
|
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.20.0 → pulp_python-3.21.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.20.0 → pulp_python-3.21.0}/pulp_python/app/migrations/0010_update_json_field.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pulp_python-3.20.0 → pulp_python-3.21.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
|
|
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.20.0 → pulp_python-3.21.0}/pulp_python/tests/functional/api/test_auto_publish.py
RENAMED
|
File without changes
|
{pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/tests/functional/api/test_consume_content.py
RENAMED
|
File without changes
|
{pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/tests/functional/api/test_crud_content_unit.py
RENAMED
|
File without changes
|
{pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/tests/functional/api/test_crud_publications.py
RENAMED
|
File without changes
|
{pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/tests/functional/api/test_crud_remotes.py
RENAMED
|
File without changes
|
|
File without changes
|
{pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/tests/functional/api/test_download_content.py
RENAMED
|
File without changes
|
{pulp_python-3.20.0 → pulp_python-3.21.0}/pulp_python/tests/functional/api/test_export_import.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
|