pulp-python 3.23.1__tar.gz → 3.24.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pulp_python-3.23.1 → pulp_python-3.24.1}/CHANGES.md +26 -2
- {pulp_python-3.23.1 → pulp_python-3.24.1}/PKG-INFO +1 -1
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/app/__init__.py +1 -1
- pulp_python-3.24.1/pulp_python/app/migrations/0019_create_missing_metadata_artifacts.py +24 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/app/utils.py +9 -6
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/tests/functional/api/test_pypi_simple_api.py +39 -32
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/tests/functional/constants.py +26 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/tests/functional/utils.py +51 -17
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python.egg-info/PKG-INFO +1 -1
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pyproject.toml +2 -2
- pulp_python-3.23.1/pulp_python/app/migrations/0019_create_missing_metadata_artifacts.py +0 -204
- {pulp_python-3.23.1 → pulp_python-3.24.1}/COMMITMENT +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/COPYRIGHT +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/LICENSE +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/MANIFEST.in +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/README.md +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/functest_requirements.txt +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/__init__.py +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/app/global_access_conditions.py +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/app/management/__init__.py +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/app/management/commands/__init__.py +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/app/management/commands/repair-python-metadata.py +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/app/migrations/0001_initial.py +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/app/migrations/0001_squashed_0010_update_json_field.py +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/app/migrations/0002_pythonpackagecontent_python_version.py +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/app/migrations/0003_new_sync_filters.py +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/app/migrations/0004_DATA_swap_distribution_model.py +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/app/migrations/0005_pythonpackagecontent_sha256.py +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/app/migrations/0006_pythonrepository_autopublish.py +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/app/migrations/0007_pythonpackagecontent_mv-2-1.py +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/app/migrations/0008_pythonpackagecontent_unique_sha256.py +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/app/migrations/0009_pythondistribution_allow_uploads.py +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/app/migrations/0010_update_json_field.py +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/app/migrations/0011_alter_pythondistribution_distribution_ptr_and_more.py +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/app/migrations/0012_add_domain.py +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/app/migrations/0013_add_rbac_permissions.py +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/app/migrations/0014_pythonpackagecontent_dynamic_and_more.py +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/app/migrations/0015_alter_pythonpackagecontent_options.py +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/app/migrations/0016_pythonpackagecontent_metadata_sha256.py +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/app/migrations/0017_pythonpackagecontent_size.py +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/app/migrations/0018_packageprovenance.py +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/app/migrations/__init__.py +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/app/modelresource.py +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/app/models.py +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/app/provenance.py +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/app/pypi/__init__.py +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/app/pypi/serializers.py +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/app/pypi/views.py +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/app/replica.py +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/app/serializers.py +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/app/settings.py +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/app/tasks/__init__.py +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/app/tasks/publish.py +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/app/tasks/repair.py +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/app/tasks/sync.py +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/app/tasks/upload.py +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/app/tasks/vulnerability_report.py +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/app/urls.py +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/app/viewsets.py +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/app/webserver_snippets/__init__.py +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/app/webserver_snippets/apache.conf +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/app/webserver_snippets/nginx.conf +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/pytest_plugin.py +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/tests/__init__.py +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/tests/functional/__init__.py +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/tests/functional/api/__init__.py +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/tests/functional/api/test_attestations.py +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/tests/functional/api/test_auto_publish.py +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/tests/functional/api/test_consume_content.py +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/tests/functional/api/test_crud_content_unit.py +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/tests/functional/api/test_crud_publications.py +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/tests/functional/api/test_crud_remotes.py +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/tests/functional/api/test_domains.py +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/tests/functional/api/test_download_content.py +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/tests/functional/api/test_export_import.py +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/tests/functional/api/test_full_mirror.py +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/tests/functional/api/test_pypi_apis.py +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/tests/functional/api/test_rbac.py +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/tests/functional/api/test_repair.py +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/tests/functional/api/test_sync.py +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/tests/functional/api/test_upload.py +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/tests/functional/api/test_vulnerability_report.py +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/tests/functional/assets/shelf-reader-0.1.tar.gz.publish.attestation +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/tests/functional/assets/shelf_reader-0.1-py2-none-any.whl.publish.attestation +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/tests/unit/__init__.py +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/tests/unit/test_models.py +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python.egg-info/SOURCES.txt +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python.egg-info/dependency_links.txt +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python.egg-info/entry_points.txt +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python.egg-info/requires.txt +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python.egg-info/top_level.txt +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/setup.cfg +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/test_requirements.txt +0 -0
- {pulp_python-3.23.1 → pulp_python-3.24.1}/unittest_requirements.txt +0 -0
|
@@ -8,9 +8,25 @@
|
|
|
8
8
|
|
|
9
9
|
[//]: # (towncrier release notes start)
|
|
10
10
|
|
|
11
|
-
## 3.
|
|
11
|
+
## 3.24.1 (2026-01-22) {: #3.24.1 }
|
|
12
12
|
|
|
13
|
-
#### Bugfixes {: #3.
|
|
13
|
+
#### Bugfixes {: #3.24.1-bugfix }
|
|
14
|
+
|
|
15
|
+
- Changed migration 19 to reset package's metadata_sha256 to null. This field will be fixed in a later release.
|
|
16
|
+
[#1071](https://github.com/pulp/pulp_python/issues/1071)
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## 3.24.0 (2026-01-20) {: #3.24.0 }
|
|
21
|
+
|
|
22
|
+
#### Features {: #3.24.0-feature }
|
|
23
|
+
|
|
24
|
+
- Added core metadata to Simple API (PEP 714)
|
|
25
|
+
[#997](https://github.com/pulp/pulp_python/issues/997)
|
|
26
|
+
- Added data-requires-python to Simple HTML API.
|
|
27
|
+
[#1054](https://github.com/pulp/pulp_python/issues/1054)
|
|
28
|
+
|
|
29
|
+
#### Bugfixes {: #3.24.0-bugfix }
|
|
14
30
|
|
|
15
31
|
- Fixed migration error in 0019_create_missing_metadata_artifacts.
|
|
16
32
|
[#1067](https://github.com/pulp/pulp_python/issues/1067)
|
|
@@ -33,6 +49,14 @@
|
|
|
33
49
|
|
|
34
50
|
---
|
|
35
51
|
|
|
52
|
+
## 3.22.2 (2026-01-06) {: #3.22.2 }
|
|
53
|
+
|
|
54
|
+
#### Bugfixes {: #3.22.2-bugfix }
|
|
55
|
+
|
|
56
|
+
- Added missing Provenance content `package` and `sha256` filters.
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
36
60
|
## 3.22.1 (2025-12-10) {: #3.22.1 }
|
|
37
61
|
|
|
38
62
|
#### Bugfixes {: #3.22.1-bugfix }
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Generated manually on 2025-12-15 14:00 for creating missing metadata artifacts
|
|
2
|
+
from django.db import migrations
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def set_metadata_sha256_null(apps, schema_editor):
|
|
6
|
+
# We can't easily create the metadata artifacts in this migration, so just set the metadata_sha256
|
|
7
|
+
# to null and we will introduce a new command later to create them.
|
|
8
|
+
PythonPackageContent = apps.get_model("python", "PythonPackageContent")
|
|
9
|
+
PythonPackageContent.objects.filter(metadata_sha256__isnull=False).update(metadata_sha256=None)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class Migration(migrations.Migration):
|
|
13
|
+
|
|
14
|
+
dependencies = [
|
|
15
|
+
("python", "0018_packageprovenance"),
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
operations = [
|
|
19
|
+
migrations.RunPython(
|
|
20
|
+
set_metadata_sha256_null,
|
|
21
|
+
reverse_code=migrations.RunPython.noop,
|
|
22
|
+
elidable=True,
|
|
23
|
+
),
|
|
24
|
+
]
|
|
@@ -47,7 +47,7 @@ simple_index_template = """<!DOCTYPE html>
|
|
|
47
47
|
</html>
|
|
48
48
|
"""
|
|
49
49
|
|
|
50
|
-
# TODO in the future: data-
|
|
50
|
+
# TODO in the future: data-yanked (not implemented yet because it is mutable)
|
|
51
51
|
simple_detail_template = """<!DOCTYPE html>
|
|
52
52
|
<html>
|
|
53
53
|
<head>
|
|
@@ -58,13 +58,14 @@ simple_detail_template = """<!DOCTYPE html>
|
|
|
58
58
|
<h1>Links for {{ project_name }}</h1>
|
|
59
59
|
{%- for pkg in project_packages %}
|
|
60
60
|
<a href="{{ pkg.url }}#sha256={{ pkg.sha256 }}" rel="internal"
|
|
61
|
-
{%- if pkg.
|
|
61
|
+
{%- if pkg.requires_python %} data-requires-python="{{ pkg.requires_python }}" {%- endif %}
|
|
62
|
+
{%- if pkg.metadata_sha256 %} data-dist-info-metadata="sha256={{ pkg.metadata_sha256 }}" data-core-metadata="sha256={{ pkg.metadata_sha256 }}"
|
|
62
63
|
{%- endif %} {% if pkg.provenance -%}
|
|
63
64
|
data-provenance="{{ pkg.provenance }}"{% endif %}>{{ pkg.filename }}</a><br/>
|
|
64
65
|
{%- endfor %}
|
|
65
66
|
</body>
|
|
66
67
|
</html>
|
|
67
|
-
"""
|
|
68
|
+
""" # noqa: E501
|
|
68
69
|
|
|
69
70
|
DIST_EXTENSIONS = {
|
|
70
71
|
".whl": "bdist_wheel",
|
|
@@ -501,7 +502,7 @@ def write_simple_index(project_names, streamed=False):
|
|
|
501
502
|
|
|
502
503
|
def write_simple_detail(project_name, project_packages, streamed=False):
|
|
503
504
|
"""Writes the simple detail page of a package."""
|
|
504
|
-
detail = Template(simple_detail_template)
|
|
505
|
+
detail = Template(simple_detail_template, autoescape=True)
|
|
505
506
|
context = {
|
|
506
507
|
"SIMPLE_API_VERSION": SIMPLE_API_VERSION,
|
|
507
508
|
"project_name": project_name,
|
|
@@ -536,12 +537,14 @@ def write_simple_detail_json(project_name, project_packages):
|
|
|
536
537
|
"data-dist-info-metadata": (
|
|
537
538
|
{"sha256": package["metadata_sha256"]} if package["metadata_sha256"] else False
|
|
538
539
|
),
|
|
540
|
+
# PEP 714
|
|
541
|
+
"core-metadata": (
|
|
542
|
+
{"sha256": package["metadata_sha256"]} if package["metadata_sha256"] else False
|
|
543
|
+
),
|
|
539
544
|
# yanked and yanked_reason are not implemented because they are mutable
|
|
540
545
|
# (v1.1, PEP 700)
|
|
541
546
|
"size": package["size"],
|
|
542
547
|
"upload-time": format_upload_time(package["upload_time"]),
|
|
543
|
-
# TODO in the future:
|
|
544
|
-
# core-metadata (PEP 7.14)
|
|
545
548
|
# (v1.3, PEP 740)
|
|
546
549
|
"provenance": package.get("provenance", None),
|
|
547
550
|
}
|
{pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/tests/functional/api/test_pypi_simple_api.py
RENAMED
|
@@ -5,17 +5,23 @@ import requests
|
|
|
5
5
|
|
|
6
6
|
from pulp_python.tests.functional.constants import (
|
|
7
7
|
PYPI_SERIAL_CONSTANT,
|
|
8
|
-
PYTHON_EGG_FILENAME,
|
|
9
|
-
PYTHON_EGG_SHA256,
|
|
10
|
-
PYTHON_EGG_URL,
|
|
11
8
|
PYTHON_SM_FIXTURE_CHECKSUMS,
|
|
12
9
|
PYTHON_SM_FIXTURE_RELEASES,
|
|
13
10
|
PYTHON_SM_PROJECT_SPECIFIER,
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
11
|
+
TWINE_EGG_FILENAME,
|
|
12
|
+
TWINE_EGG_REQUIRES_PYTHON,
|
|
13
|
+
TWINE_EGG_SHA256,
|
|
14
|
+
TWINE_EGG_SIZE,
|
|
15
|
+
TWINE_EGG_URL,
|
|
16
|
+
TWINE_FIXTURE_CHECKSUMS,
|
|
17
|
+
TWINE_FIXTURE_METADATA_SHA256,
|
|
18
|
+
TWINE_FIXTURE_REQUIRES_PYTHON,
|
|
19
|
+
TWINE_WHEEL_FILENAME,
|
|
20
|
+
TWINE_WHEEL_METADATA_SHA256,
|
|
21
|
+
TWINE_WHEEL_REQUIRES_PYTHON,
|
|
22
|
+
TWINE_WHEEL_SHA256,
|
|
23
|
+
TWINE_WHEEL_SIZE,
|
|
24
|
+
TWINE_WHEEL_URL,
|
|
19
25
|
)
|
|
20
26
|
from pulp_python.tests.functional.utils import ensure_simple
|
|
21
27
|
|
|
@@ -55,30 +61,27 @@ def test_simple_html_detail_api(
|
|
|
55
61
|
python_distribution_factory,
|
|
56
62
|
python_repo_factory,
|
|
57
63
|
):
|
|
58
|
-
content_1 = python_content_factory(
|
|
59
|
-
content_2 = python_content_factory(
|
|
64
|
+
content_1 = python_content_factory(TWINE_WHEEL_FILENAME, url=TWINE_WHEEL_URL)
|
|
65
|
+
content_2 = python_content_factory(TWINE_EGG_FILENAME, url=TWINE_EGG_URL)
|
|
60
66
|
body = {"add_content_units": [content_1.pulp_href, content_2.pulp_href]}
|
|
61
67
|
|
|
62
68
|
repo = python_repo_factory()
|
|
63
69
|
monitor_task(python_bindings.RepositoriesPythonApi.modify(repo.pulp_href, body).task)
|
|
64
70
|
distro = python_distribution_factory(repository=repo)
|
|
65
71
|
|
|
66
|
-
url = f'{urljoin(distro.base_url, "simple/")}
|
|
72
|
+
url = f'{urljoin(distro.base_url, "simple/")}twine'
|
|
67
73
|
headers = {"Accept": PYPI_SIMPLE_V1_HTML}
|
|
68
74
|
|
|
69
75
|
response = requests.get(url, headers=headers)
|
|
70
76
|
assert response.headers["Content-Type"] == PYPI_SIMPLE_V1_HTML
|
|
71
77
|
assert response.headers["X-PyPI-Last-Serial"] == str(PYPI_SERIAL_CONSTANT)
|
|
72
78
|
|
|
73
|
-
metadata_sha_digests = {
|
|
74
|
-
PYTHON_WHEEL_FILENAME: PYTHON_WHEEL_METADATA_SHA256,
|
|
75
|
-
PYTHON_EGG_FILENAME: None, # egg files should not have metadata
|
|
76
|
-
}
|
|
77
79
|
proper, msgs = ensure_simple(
|
|
78
80
|
urljoin(distro.base_url, "simple/"),
|
|
79
|
-
{"
|
|
80
|
-
sha_digests=
|
|
81
|
-
metadata_sha_digests=
|
|
81
|
+
{"twine": [TWINE_WHEEL_FILENAME, TWINE_EGG_FILENAME]},
|
|
82
|
+
sha_digests=TWINE_FIXTURE_CHECKSUMS,
|
|
83
|
+
metadata_sha_digests=TWINE_FIXTURE_METADATA_SHA256,
|
|
84
|
+
requires_python=TWINE_FIXTURE_REQUIRES_PYTHON,
|
|
82
85
|
)
|
|
83
86
|
assert proper, f"Simple API validation failed: {msgs}"
|
|
84
87
|
|
|
@@ -114,15 +117,15 @@ def test_simple_json_detail_api(
|
|
|
114
117
|
python_distribution_factory,
|
|
115
118
|
python_repo_factory,
|
|
116
119
|
):
|
|
117
|
-
content_1 = python_content_factory(
|
|
118
|
-
content_2 = python_content_factory(
|
|
120
|
+
content_1 = python_content_factory(TWINE_WHEEL_FILENAME, url=TWINE_WHEEL_URL)
|
|
121
|
+
content_2 = python_content_factory(TWINE_EGG_FILENAME, url=TWINE_EGG_URL)
|
|
119
122
|
body = {"add_content_units": [content_1.pulp_href, content_2.pulp_href]}
|
|
120
123
|
|
|
121
124
|
repo = python_repo_factory()
|
|
122
125
|
monitor_task(python_bindings.RepositoriesPythonApi.modify(repo.pulp_href, body).task)
|
|
123
126
|
distro = python_distribution_factory(repository=repo)
|
|
124
127
|
|
|
125
|
-
url = f'{urljoin(distro.base_url, "simple/")}
|
|
128
|
+
url = f'{urljoin(distro.base_url, "simple/")}twine'
|
|
126
129
|
headers = {"Accept": PYPI_SIMPLE_V1_JSON}
|
|
127
130
|
|
|
128
131
|
response = requests.get(url, headers=headers)
|
|
@@ -131,27 +134,31 @@ def test_simple_json_detail_api(
|
|
|
131
134
|
|
|
132
135
|
data = response.json()
|
|
133
136
|
assert data["meta"] == {"api-version": API_VERSION, "_last-serial": PYPI_SERIAL_CONSTANT}
|
|
134
|
-
assert data["name"] == "
|
|
137
|
+
assert data["name"] == "twine"
|
|
135
138
|
assert data["files"]
|
|
136
|
-
assert data["versions"] == ["
|
|
139
|
+
assert data["versions"] == ["5.1.0"]
|
|
137
140
|
|
|
138
141
|
# Check data of a wheel
|
|
139
|
-
file_whl = next((i for i in data["files"] if i["filename"] ==
|
|
142
|
+
file_whl = next((i for i in data["files"] if i["filename"] == TWINE_WHEEL_FILENAME), None)
|
|
140
143
|
assert file_whl is not None, "wheel file not found"
|
|
141
144
|
assert file_whl["url"]
|
|
142
|
-
assert file_whl["hashes"] == {"sha256":
|
|
143
|
-
assert file_whl["requires-python"]
|
|
144
|
-
assert file_whl["data-dist-info-metadata"] == {"sha256":
|
|
145
|
-
assert file_whl["
|
|
145
|
+
assert file_whl["hashes"] == {"sha256": TWINE_WHEEL_SHA256}
|
|
146
|
+
assert file_whl["requires-python"] == TWINE_WHEEL_REQUIRES_PYTHON
|
|
147
|
+
assert file_whl["data-dist-info-metadata"] == {"sha256": TWINE_WHEEL_METADATA_SHA256}
|
|
148
|
+
assert file_whl["core-metadata"] == {"sha256": TWINE_WHEEL_METADATA_SHA256}
|
|
149
|
+
assert file_whl["size"] == TWINE_WHEEL_SIZE
|
|
146
150
|
assert file_whl["upload-time"] is not None
|
|
151
|
+
assert file_whl["provenance"] is None
|
|
152
|
+
|
|
147
153
|
# Check data of a tarball
|
|
148
|
-
file_tar = next((i for i in data["files"] if i["filename"] ==
|
|
154
|
+
file_tar = next((i for i in data["files"] if i["filename"] == TWINE_EGG_FILENAME), None)
|
|
149
155
|
assert file_tar is not None, "tar file not found"
|
|
150
156
|
assert file_tar["url"]
|
|
151
|
-
assert file_tar["hashes"] == {"sha256":
|
|
152
|
-
assert file_tar["requires-python"]
|
|
157
|
+
assert file_tar["hashes"] == {"sha256": TWINE_EGG_SHA256}
|
|
158
|
+
assert file_tar["requires-python"] == TWINE_EGG_REQUIRES_PYTHON
|
|
153
159
|
assert file_tar["data-dist-info-metadata"] is False
|
|
154
|
-
assert file_tar["
|
|
160
|
+
assert file_tar["core-metadata"] is False
|
|
161
|
+
assert file_tar["size"] == TWINE_EGG_SIZE
|
|
155
162
|
assert file_tar["upload-time"] is not None
|
|
156
163
|
assert file_tar["provenance"] is None
|
|
157
164
|
|
|
@@ -226,6 +226,32 @@ PYTHON_INFO_DATA = {
|
|
|
226
226
|
# maybe add description, license is long for this one
|
|
227
227
|
}
|
|
228
228
|
|
|
229
|
+
# twine pkg data for PyPI Simple API
|
|
230
|
+
TWINE_EGG_FILENAME = "twine-5.1.0.tar.gz"
|
|
231
|
+
TWINE_EGG_URL = urljoin(urljoin(PYTHON_FIXTURES_URL, "packages/"), TWINE_EGG_FILENAME)
|
|
232
|
+
TWINE_EGG_SHA256 = "4d74770c88c4fcaf8134d2a6a9d863e40f08255ff7d8e2acb3cbbd57d25f6e9d"
|
|
233
|
+
TWINE_EGG_SIZE = 224997
|
|
234
|
+
TWINE_EGG_REQUIRES_PYTHON = ">=3.8"
|
|
235
|
+
|
|
236
|
+
TWINE_WHEEL_FILENAME = "twine-5.1.0-py3-none-any.whl"
|
|
237
|
+
TWINE_WHEEL_URL = urljoin(urljoin(PYTHON_FIXTURES_URL, "packages/"), TWINE_WHEEL_FILENAME)
|
|
238
|
+
TWINE_WHEEL_SHA256 = "fe1d814395bfe50cfbe27783cb74efe93abeac3f66deaeb6c8390e4e92bacb43"
|
|
239
|
+
TWINE_WHEEL_SIZE = 38563
|
|
240
|
+
TWINE_WHEEL_REQUIRES_PYTHON = ">=3.8"
|
|
241
|
+
TWINE_WHEEL_METADATA_SHA256 = "0ac5cf457bd47512b3477949ff6274cc2258414f3e1f136e049585aac92e4ddb"
|
|
242
|
+
|
|
243
|
+
TWINE_FIXTURE_CHECKSUMS = {
|
|
244
|
+
TWINE_EGG_FILENAME: TWINE_EGG_SHA256,
|
|
245
|
+
TWINE_WHEEL_FILENAME: TWINE_WHEEL_SHA256,
|
|
246
|
+
}
|
|
247
|
+
TWINE_FIXTURE_METADATA_SHA256 = {
|
|
248
|
+
TWINE_WHEEL_FILENAME: TWINE_WHEEL_METADATA_SHA256,
|
|
249
|
+
TWINE_EGG_FILENAME: None, # egg files should not have metadata
|
|
250
|
+
}
|
|
251
|
+
TWINE_FIXTURE_REQUIRES_PYTHON = {
|
|
252
|
+
TWINE_WHEEL_FILENAME: TWINE_EGG_REQUIRES_PYTHON,
|
|
253
|
+
TWINE_EGG_FILENAME: TWINE_WHEEL_REQUIRES_PYTHON,
|
|
254
|
+
}
|
|
229
255
|
|
|
230
256
|
# Current tests use PYTHON_FIXTURES_URL with an 'S', remove after adding api tests
|
|
231
257
|
PYTHON_FIXTURE_URL = urljoin(PULP_FIXTURES_BASE_URL, "python-pypi/")
|
|
@@ -6,27 +6,55 @@ from lxml import html
|
|
|
6
6
|
|
|
7
7
|
def _validate_metadata_sha_digest(link, filename, metadata_sha_digests):
|
|
8
8
|
"""
|
|
9
|
-
Validate data-dist-info-metadata
|
|
9
|
+
Validate data-dist-info-metadata and data-core-metadata attributes for a release link.
|
|
10
10
|
"""
|
|
11
|
-
|
|
11
|
+
expected_metadata_sha = metadata_sha_digests.get(filename)
|
|
12
|
+
expected_attr = f"sha256={expected_metadata_sha}" if expected_metadata_sha else None
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
f"\nFile {filename} should not have
|
|
24
|
-
|
|
14
|
+
msgs = ""
|
|
15
|
+
for attr_name in ["data-dist-info-metadata", "data-core-metadata"]:
|
|
16
|
+
attr_value = link.get(attr_name)
|
|
17
|
+
if attr_value != expected_attr:
|
|
18
|
+
if expected_attr:
|
|
19
|
+
msgs += (
|
|
20
|
+
f"\nFile {filename} has incorrect {attr_name}: "
|
|
21
|
+
f"expected '{expected_attr}', got '{attr_value}'"
|
|
22
|
+
)
|
|
23
|
+
else:
|
|
24
|
+
msgs += f"\nFile {filename} should not have {attr_name} but has '{attr_value}'"
|
|
25
|
+
return msgs
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _validate_requires_python(link, filename, requires_python, page_content):
|
|
29
|
+
"""
|
|
30
|
+
Validate data-requires-python attribute for a release link.
|
|
31
|
+
"""
|
|
32
|
+
expected_requires_python = requires_python.get(filename) if requires_python else None
|
|
33
|
+
attr_value = link.get("data-requires-python")
|
|
34
|
+
|
|
35
|
+
msgs = ""
|
|
36
|
+
if attr_value != expected_requires_python:
|
|
37
|
+
if expected_requires_python:
|
|
38
|
+
msgs += (
|
|
39
|
+
f"\nFile {filename} has incorrect data-requires-python: "
|
|
40
|
+
f"expected '{expected_requires_python}', got '{attr_value}'"
|
|
25
41
|
)
|
|
26
|
-
|
|
42
|
+
else:
|
|
43
|
+
msgs += f"\nFile {filename} should not have data-requires-python but has '{attr_value}'"
|
|
44
|
+
|
|
45
|
+
# Check HTML escaping
|
|
46
|
+
if expected_requires_python and any(char in expected_requires_python for char in [">", "<"]):
|
|
47
|
+
escaped_value = expected_requires_python.replace(">", ">").replace("<", "<")
|
|
48
|
+
escaped_attr = f'data-requires-python="{escaped_value}"'
|
|
49
|
+
if escaped_attr not in page_content:
|
|
50
|
+
msgs += f"\nFile {filename} has unescaped < or > in data-requires-python attribute"
|
|
51
|
+
|
|
52
|
+
return msgs
|
|
27
53
|
|
|
28
54
|
|
|
29
|
-
def ensure_simple(
|
|
55
|
+
def ensure_simple(
|
|
56
|
+
simple_url, packages, sha_digests=None, metadata_sha_digests=None, requires_python=None
|
|
57
|
+
):
|
|
30
58
|
"""
|
|
31
59
|
Tests that the simple api at `url` matches the packages supplied.
|
|
32
60
|
`packages`: dictionary of form {package_name: [release_filenames]}
|
|
@@ -41,7 +69,8 @@ def ensure_simple(simple_url, packages, sha_digests=None, metadata_sha_digests=N
|
|
|
41
69
|
|
|
42
70
|
def explore_links(page_url, page_name, links_found, msgs):
|
|
43
71
|
legit_found_links = []
|
|
44
|
-
|
|
72
|
+
page_content = requests.get(page_url).text
|
|
73
|
+
page = html.fromstring(page_content)
|
|
45
74
|
page_links = page.xpath("/html/body/a")
|
|
46
75
|
for link in page_links:
|
|
47
76
|
if link.text in links_found:
|
|
@@ -53,6 +82,11 @@ def ensure_simple(simple_url, packages, sha_digests=None, metadata_sha_digests=N
|
|
|
53
82
|
# Check metadata SHA digest if provided
|
|
54
83
|
if metadata_sha_digests and page_name == "release":
|
|
55
84
|
msgs += _validate_metadata_sha_digest(link, link.text, metadata_sha_digests)
|
|
85
|
+
# Check requires-python if provided
|
|
86
|
+
if requires_python and page_name == "release":
|
|
87
|
+
msgs += _validate_requires_python(
|
|
88
|
+
link, link.text, requires_python, page_content
|
|
89
|
+
)
|
|
56
90
|
else:
|
|
57
91
|
msgs += f"\nFound {page_name} link without href {link.text}"
|
|
58
92
|
else:
|
|
@@ -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.24.1"
|
|
11
11
|
description = "pulp-python plugin for the Pulp Project"
|
|
12
12
|
readme = "README.md"
|
|
13
13
|
authors = [
|
|
@@ -77,7 +77,7 @@ ignore = [
|
|
|
77
77
|
[tool.bumpversion]
|
|
78
78
|
# This section is managed by the plugin template. Do not edit manually.
|
|
79
79
|
|
|
80
|
-
current_version = "3.
|
|
80
|
+
current_version = "3.24.1"
|
|
81
81
|
commit = false
|
|
82
82
|
tag = false
|
|
83
83
|
parse = "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<alpha>0a)?(?P<patch>\\d+)(\\.(?P<release>[a-z]+))?"
|
|
@@ -1,204 +0,0 @@
|
|
|
1
|
-
# Generated manually on 2025-12-15 14:00 for creating missing metadata artifacts
|
|
2
|
-
|
|
3
|
-
from django.db import migrations
|
|
4
|
-
|
|
5
|
-
BATCH_SIZE = 1000
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
def pulp_hashlib_new(name, *args, **kwargs):
|
|
9
|
-
"""
|
|
10
|
-
Copied and updated (to comply with migrations) from pulpcore.
|
|
11
|
-
"""
|
|
12
|
-
import hashlib as the_real_hashlib
|
|
13
|
-
from django.conf import settings
|
|
14
|
-
|
|
15
|
-
if name not in settings.ALLOWED_CONTENT_CHECKSUMS:
|
|
16
|
-
return None
|
|
17
|
-
|
|
18
|
-
return the_real_hashlib.new(name, *args, **kwargs)
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
def init_and_validate(file, artifact_model, expected_digests):
|
|
22
|
-
"""
|
|
23
|
-
Copied and updated (to comply with migrations) from pulpcore.
|
|
24
|
-
"""
|
|
25
|
-
from django.conf import settings
|
|
26
|
-
|
|
27
|
-
digest_fields = []
|
|
28
|
-
for alg in ("sha512", "sha384", "sha256", "sha224", "sha1", "md5"):
|
|
29
|
-
if alg in settings.ALLOWED_CONTENT_CHECKSUMS:
|
|
30
|
-
digest_fields.append(alg)
|
|
31
|
-
|
|
32
|
-
if isinstance(file, str):
|
|
33
|
-
with open(file, "rb") as f:
|
|
34
|
-
hashers = {
|
|
35
|
-
n: hasher for n in digest_fields if (hasher := pulp_hashlib_new(n)) is not None
|
|
36
|
-
}
|
|
37
|
-
if not hashers:
|
|
38
|
-
return None
|
|
39
|
-
|
|
40
|
-
size = 0
|
|
41
|
-
while True:
|
|
42
|
-
chunk = f.read(1048576) # 1 megabyte
|
|
43
|
-
if not chunk:
|
|
44
|
-
break
|
|
45
|
-
for algorithm in hashers.values():
|
|
46
|
-
algorithm.update(chunk)
|
|
47
|
-
size = size + len(chunk)
|
|
48
|
-
else:
|
|
49
|
-
size = file.size
|
|
50
|
-
hashers = file.hashers
|
|
51
|
-
|
|
52
|
-
mismatched_sha256 = None
|
|
53
|
-
for algorithm, expected_digest in expected_digests.items():
|
|
54
|
-
if algorithm not in hashers:
|
|
55
|
-
return None
|
|
56
|
-
actual_digest = hashers[algorithm].hexdigest()
|
|
57
|
-
if expected_digest != actual_digest:
|
|
58
|
-
# Store the actual value for later fixing if it differs from the package value
|
|
59
|
-
mismatched_sha256 = actual_digest
|
|
60
|
-
|
|
61
|
-
attributes = {"size": size, "file": file}
|
|
62
|
-
for algorithm in digest_fields:
|
|
63
|
-
attributes[algorithm] = hashers[algorithm].hexdigest()
|
|
64
|
-
|
|
65
|
-
return artifact_model(**attributes), mismatched_sha256
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
def extract_wheel_metadata(filename):
|
|
69
|
-
"""
|
|
70
|
-
Extract the metadata file content from a wheel file.
|
|
71
|
-
Return the raw metadata content as bytes or None if metadata cannot be extracted.
|
|
72
|
-
"""
|
|
73
|
-
import zipfile
|
|
74
|
-
|
|
75
|
-
try:
|
|
76
|
-
with zipfile.ZipFile(filename, "r") as f:
|
|
77
|
-
for file_path in f.namelist():
|
|
78
|
-
if file_path.endswith(".dist-info/METADATA"):
|
|
79
|
-
return f.read(file_path)
|
|
80
|
-
except (zipfile.BadZipFile, KeyError, OSError):
|
|
81
|
-
pass
|
|
82
|
-
return None
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
def artifact_to_metadata_artifact(filename, artifact, md_digests, tmp_dir, artifact_model):
|
|
86
|
-
"""
|
|
87
|
-
Create artifact for metadata from the provided wheel artifact.
|
|
88
|
-
Return (artifact, mismatched_sha256) on success, None on any failure.
|
|
89
|
-
"""
|
|
90
|
-
import shutil
|
|
91
|
-
import tempfile
|
|
92
|
-
|
|
93
|
-
with tempfile.NamedTemporaryFile("wb", dir=tmp_dir, suffix=filename, delete=False) as temp_file:
|
|
94
|
-
temp_wheel_path = temp_file.name
|
|
95
|
-
artifact.file.seek(0)
|
|
96
|
-
shutil.copyfileobj(artifact.file, temp_file)
|
|
97
|
-
temp_file.flush()
|
|
98
|
-
|
|
99
|
-
metadata_content = extract_wheel_metadata(temp_wheel_path)
|
|
100
|
-
if not metadata_content:
|
|
101
|
-
return None
|
|
102
|
-
|
|
103
|
-
with tempfile.NamedTemporaryFile(
|
|
104
|
-
"wb", dir=tmp_dir, suffix=".metadata", delete=False
|
|
105
|
-
) as temp_md:
|
|
106
|
-
temp_metadata_path = temp_md.name
|
|
107
|
-
temp_md.write(metadata_content)
|
|
108
|
-
temp_md.flush()
|
|
109
|
-
|
|
110
|
-
return init_and_validate(temp_metadata_path, artifact_model, md_digests)
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
def create_missing_metadata_artifacts(apps, schema_editor):
|
|
114
|
-
"""
|
|
115
|
-
Create metadata artifacts for PythonPackageContent instances that have metadata_sha256
|
|
116
|
-
but are missing the corresponding metadata artifact.
|
|
117
|
-
"""
|
|
118
|
-
import tempfile
|
|
119
|
-
from django.conf import settings
|
|
120
|
-
from django.db import models
|
|
121
|
-
|
|
122
|
-
PythonPackageContent = apps.get_model("python", "PythonPackageContent")
|
|
123
|
-
ContentArtifact = apps.get_model("core", "ContentArtifact")
|
|
124
|
-
Artifact = apps.get_model("core", "Artifact")
|
|
125
|
-
|
|
126
|
-
packages = (
|
|
127
|
-
PythonPackageContent.objects.filter(
|
|
128
|
-
metadata_sha256__isnull=False,
|
|
129
|
-
filename__endswith=".whl",
|
|
130
|
-
contentartifact__artifact__isnull=False,
|
|
131
|
-
contentartifact__relative_path=models.F("filename"),
|
|
132
|
-
)
|
|
133
|
-
.exclude(metadata_sha256="")
|
|
134
|
-
.prefetch_related("_artifacts")
|
|
135
|
-
.only("filename", "metadata_sha256")
|
|
136
|
-
)
|
|
137
|
-
artifact_batch = []
|
|
138
|
-
contentartifact_batch = []
|
|
139
|
-
packages_batch = []
|
|
140
|
-
|
|
141
|
-
with tempfile.TemporaryDirectory(dir=settings.WORKING_DIRECTORY) as temp_dir:
|
|
142
|
-
for package in packages:
|
|
143
|
-
# Get the main artifact for package
|
|
144
|
-
main_artifact = package._artifacts.get()
|
|
145
|
-
|
|
146
|
-
filename = package.filename
|
|
147
|
-
metadata_digests = {"sha256": package.metadata_sha256}
|
|
148
|
-
result = artifact_to_metadata_artifact(
|
|
149
|
-
filename, main_artifact, metadata_digests, temp_dir, Artifact
|
|
150
|
-
)
|
|
151
|
-
if result is None:
|
|
152
|
-
# Unset metadata_sha256 when extraction or validation fails
|
|
153
|
-
package.metadata_sha256 = None
|
|
154
|
-
packages_batch.append(package)
|
|
155
|
-
continue
|
|
156
|
-
metadata_artifact, mismatched_sha256 = result
|
|
157
|
-
if mismatched_sha256:
|
|
158
|
-
# Fix the package if its metadata_sha256 differs from the actual value
|
|
159
|
-
package.metadata_sha256 = mismatched_sha256
|
|
160
|
-
packages_batch.append(package)
|
|
161
|
-
|
|
162
|
-
# Set the domain on the metadata artifact to match the package's domain
|
|
163
|
-
metadata_artifact.pulp_domain = package._pulp_domain
|
|
164
|
-
|
|
165
|
-
contentartifact = ContentArtifact(
|
|
166
|
-
artifact=metadata_artifact,
|
|
167
|
-
content=package,
|
|
168
|
-
relative_path=f"{filename}.metadata",
|
|
169
|
-
)
|
|
170
|
-
artifact_batch.append(metadata_artifact)
|
|
171
|
-
contentartifact_batch.append(contentartifact)
|
|
172
|
-
|
|
173
|
-
if len(artifact_batch) == BATCH_SIZE:
|
|
174
|
-
Artifact.objects.bulk_create(artifact_batch, batch_size=BATCH_SIZE)
|
|
175
|
-
ContentArtifact.objects.bulk_create(contentartifact_batch, batch_size=BATCH_SIZE)
|
|
176
|
-
artifact_batch.clear()
|
|
177
|
-
contentartifact_batch.clear()
|
|
178
|
-
if len(packages_batch) == BATCH_SIZE:
|
|
179
|
-
PythonPackageContent.objects.bulk_update(
|
|
180
|
-
packages_batch, ["metadata_sha256"], batch_size=BATCH_SIZE
|
|
181
|
-
)
|
|
182
|
-
packages_batch.clear()
|
|
183
|
-
|
|
184
|
-
if artifact_batch:
|
|
185
|
-
Artifact.objects.bulk_create(artifact_batch, batch_size=BATCH_SIZE)
|
|
186
|
-
ContentArtifact.objects.bulk_create(contentartifact_batch, batch_size=BATCH_SIZE)
|
|
187
|
-
if packages_batch:
|
|
188
|
-
PythonPackageContent.objects.bulk_update(
|
|
189
|
-
packages_batch, ["metadata_sha256"], batch_size=BATCH_SIZE
|
|
190
|
-
)
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
class Migration(migrations.Migration):
|
|
194
|
-
|
|
195
|
-
dependencies = [
|
|
196
|
-
("python", "0018_packageprovenance"),
|
|
197
|
-
]
|
|
198
|
-
|
|
199
|
-
operations = [
|
|
200
|
-
migrations.RunPython(
|
|
201
|
-
create_missing_metadata_artifacts,
|
|
202
|
-
reverse_code=migrations.RunPython.noop,
|
|
203
|
-
),
|
|
204
|
-
]
|
|
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.23.1 → pulp_python-3.24.1}/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.23.1 → pulp_python-3.24.1}/pulp_python/app/migrations/0010_update_json_field.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pulp_python-3.23.1 → pulp_python-3.24.1}/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.23.1 → pulp_python-3.24.1}/pulp_python/app/migrations/0018_packageprovenance.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
|
{pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/tests/functional/api/test_attestations.py
RENAMED
|
File without changes
|
{pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/tests/functional/api/test_auto_publish.py
RENAMED
|
File without changes
|
{pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/tests/functional/api/test_consume_content.py
RENAMED
|
File without changes
|
{pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/tests/functional/api/test_crud_content_unit.py
RENAMED
|
File without changes
|
{pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/tests/functional/api/test_crud_publications.py
RENAMED
|
File without changes
|
{pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/tests/functional/api/test_crud_remotes.py
RENAMED
|
File without changes
|
|
File without changes
|
{pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/tests/functional/api/test_download_content.py
RENAMED
|
File without changes
|
{pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/tests/functional/api/test_export_import.py
RENAMED
|
File without changes
|
{pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/tests/functional/api/test_full_mirror.py
RENAMED
|
File without changes
|
{pulp_python-3.23.1 → pulp_python-3.24.1}/pulp_python/tests/functional/api/test_pypi_apis.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
|