pulp-python 3.29.0__py3-none-any.whl → 3.30.1__py3-none-any.whl
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/app/__init__.py +5 -3
- pulp_python/app/management/commands/repair-python-metadata.py +7 -3
- pulp_python/app/modelresource.py +1 -0
- pulp_python/app/models.py +16 -14
- pulp_python/app/pypi/serializers.py +7 -5
- pulp_python/app/pypi/views.py +40 -28
- pulp_python/app/replica.py +3 -2
- pulp_python/app/serializers.py +17 -16
- pulp_python/app/tasks/publish.py +2 -2
- pulp_python/app/tasks/repair.py +4 -2
- pulp_python/app/tasks/sync.py +13 -15
- pulp_python/app/tasks/upload.py +7 -6
- pulp_python/app/urls.py +2 -2
- pulp_python/app/utils.py +23 -9
- pulp_python/app/viewsets.py +3 -1
- pulp_python/pytest_plugin.py +8 -6
- pulp_python/tests/functional/api/test_attestations.py +2 -2
- pulp_python/tests/functional/api/test_blocklist.py +1 -0
- pulp_python/tests/functional/api/test_consume_content.py +0 -1
- pulp_python/tests/functional/api/test_crud_content_unit.py +5 -4
- pulp_python/tests/functional/api/test_crud_publications.py +6 -5
- pulp_python/tests/functional/api/test_crud_remotes.py +3 -2
- pulp_python/tests/functional/api/test_domains.py +6 -5
- pulp_python/tests/functional/api/test_download_content.py +2 -2
- pulp_python/tests/functional/api/test_export_import.py +5 -3
- pulp_python/tests/functional/api/test_full_mirror.py +9 -9
- pulp_python/tests/functional/api/test_pypi_apis.py +48 -5
- pulp_python/tests/functional/api/test_pypi_simple_api.py +5 -6
- pulp_python/tests/functional/api/test_rbac.py +5 -4
- pulp_python/tests/functional/api/test_repair.py +2 -1
- pulp_python/tests/functional/api/test_sync.py +11 -11
- pulp_python/tests/functional/api/test_upload.py +5 -3
- pulp_python/tests/functional/constants.py +4 -0
- pulp_python/tests/functional/utils.py +2 -2
- {pulp_python-3.29.0.dist-info → pulp_python-3.30.1.dist-info}/METADATA +1 -1
- {pulp_python-3.29.0.dist-info → pulp_python-3.30.1.dist-info}/RECORD +40 -40
- {pulp_python-3.29.0.dist-info → pulp_python-3.30.1.dist-info}/WHEEL +0 -0
- {pulp_python-3.29.0.dist-info → pulp_python-3.30.1.dist-info}/entry_points.txt +0 -0
- {pulp_python-3.29.0.dist-info → pulp_python-3.30.1.dist-info}/licenses/LICENSE +0 -0
- {pulp_python-3.29.0.dist-info → pulp_python-3.30.1.dist-info}/top_level.txt +0 -0
pulp_python/app/__init__.py
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
from gettext import gettext as _
|
|
2
|
+
|
|
1
3
|
from django.db.models.signals import post_migrate
|
|
4
|
+
|
|
2
5
|
from pulpcore.plugin import PulpPluginAppConfig
|
|
3
|
-
from gettext import gettext as _
|
|
4
6
|
|
|
5
7
|
|
|
6
8
|
class PulpPythonPluginAppConfig(PulpPluginAppConfig):
|
|
@@ -10,7 +12,7 @@ class PulpPythonPluginAppConfig(PulpPluginAppConfig):
|
|
|
10
12
|
|
|
11
13
|
name = "pulp_python.app"
|
|
12
14
|
label = "python"
|
|
13
|
-
version = "3.
|
|
15
|
+
version = "3.30.1"
|
|
14
16
|
python_package_name = "pulp-python"
|
|
15
17
|
domain_compatible = True
|
|
16
18
|
|
|
@@ -26,7 +28,7 @@ class PulpPythonPluginAppConfig(PulpPluginAppConfig):
|
|
|
26
28
|
|
|
27
29
|
# TODO: Remove this when https://github.com/pulp/pulpcore/issues/5500 is resolved
|
|
28
30
|
def _populate_pypi_access_policies(sender, apps, verbosity, **kwargs):
|
|
29
|
-
from pulp_python.app.pypi.views import PyPIView, SimpleView, UploadView
|
|
31
|
+
from pulp_python.app.pypi.views import MetadataView, PyPIView, SimpleView, UploadView
|
|
30
32
|
|
|
31
33
|
try:
|
|
32
34
|
AccessPolicy = apps.get_model("core", "AccessPolicy")
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import re
|
|
2
1
|
import os
|
|
3
|
-
|
|
2
|
+
import re
|
|
4
3
|
from gettext import gettext as _
|
|
5
4
|
|
|
6
5
|
from django.conf import settings
|
|
6
|
+
from django.core.management import BaseCommand, CommandError
|
|
7
7
|
|
|
8
8
|
from pulpcore.plugin.util import extract_pk
|
|
9
|
+
|
|
9
10
|
from pulp_python.app.models import PythonPackageContent, PythonRepository
|
|
10
11
|
from pulp_python.app.utils import artifact_to_python_content_data
|
|
11
12
|
|
|
@@ -78,7 +79,10 @@ class Command(BaseCommand):
|
|
|
78
79
|
Management command to repair metadata of PythonPackageContent.
|
|
79
80
|
"""
|
|
80
81
|
|
|
81
|
-
help = _(
|
|
82
|
+
help = _(
|
|
83
|
+
"[Deprecated] Use the repository `repair_metadata` task instead. "
|
|
84
|
+
"Repair the metadata of PythonPackageContent stored in PythonRepositories."
|
|
85
|
+
)
|
|
82
86
|
|
|
83
87
|
def add_arguments(self, parser):
|
|
84
88
|
"""Set up arguments."""
|
pulp_python/app/modelresource.py
CHANGED
pulp_python/app/models.py
CHANGED
|
@@ -1,44 +1,45 @@
|
|
|
1
1
|
import hashlib
|
|
2
2
|
import json
|
|
3
3
|
from logging import getLogger
|
|
4
|
+
from pathlib import PurePath
|
|
4
5
|
|
|
5
6
|
from aiohttp.web import json_response
|
|
7
|
+
from django.conf import settings
|
|
6
8
|
from django.contrib.postgres.fields import ArrayField
|
|
7
9
|
from django.core.exceptions import ObjectDoesNotExist
|
|
8
10
|
from django.db import models
|
|
9
|
-
from django.conf import settings
|
|
10
11
|
from django_lifecycle import (
|
|
11
12
|
BEFORE_SAVE,
|
|
12
13
|
hook,
|
|
13
14
|
)
|
|
14
15
|
from rest_framework.serializers import ValidationError
|
|
16
|
+
|
|
15
17
|
from pulpcore.plugin.models import (
|
|
16
18
|
AutoAddObjPermsMixin,
|
|
17
19
|
BaseModel,
|
|
18
20
|
Content,
|
|
19
|
-
Publication,
|
|
20
21
|
Distribution,
|
|
22
|
+
Publication,
|
|
21
23
|
Remote,
|
|
22
24
|
Repository,
|
|
23
25
|
)
|
|
26
|
+
from pulpcore.plugin.repo_version_utils import (
|
|
27
|
+
collect_duplicates,
|
|
28
|
+
remove_duplicates,
|
|
29
|
+
validate_repo_version,
|
|
30
|
+
)
|
|
24
31
|
from pulpcore.plugin.responses import ArtifactResponse
|
|
32
|
+
from pulpcore.plugin.util import get_domain, get_domain_pk
|
|
25
33
|
|
|
26
|
-
from pathlib import PurePath
|
|
27
34
|
from .provenance import Provenance
|
|
28
35
|
from .utils import (
|
|
29
|
-
|
|
36
|
+
PYPI_LAST_SERIAL,
|
|
37
|
+
PYPI_SERIAL_CONSTANT,
|
|
30
38
|
artifact_to_metadata_artifact,
|
|
39
|
+
artifact_to_python_content_data,
|
|
31
40
|
canonicalize_name,
|
|
32
41
|
python_content_to_json,
|
|
33
|
-
PYPI_LAST_SERIAL,
|
|
34
|
-
PYPI_SERIAL_CONSTANT,
|
|
35
|
-
)
|
|
36
|
-
from pulpcore.plugin.repo_version_utils import (
|
|
37
|
-
collect_duplicates,
|
|
38
|
-
remove_duplicates,
|
|
39
|
-
validate_repo_version,
|
|
40
42
|
)
|
|
41
|
-
from pulpcore.plugin.util import get_domain_pk, get_domain
|
|
42
43
|
|
|
43
44
|
log = getLogger(__name__)
|
|
44
45
|
|
|
@@ -453,8 +454,9 @@ class PythonRepository(Repository, AutoAddObjPermsMixin):
|
|
|
453
454
|
break
|
|
454
455
|
if blocked:
|
|
455
456
|
raise ValidationError(
|
|
456
|
-
"Blocklisted packages cannot be added to this repository: "
|
|
457
|
-
|
|
457
|
+
"Blocklisted packages cannot be added to this repository: {}".format(
|
|
458
|
+
", ".join(blocked)
|
|
459
|
+
)
|
|
458
460
|
)
|
|
459
461
|
|
|
460
462
|
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
from gettext import gettext as _
|
|
3
3
|
|
|
4
|
-
from
|
|
4
|
+
from django.db.utils import IntegrityError
|
|
5
5
|
from pydantic import TypeAdapter, ValidationError
|
|
6
|
-
from
|
|
7
|
-
|
|
6
|
+
from rest_framework import serializers
|
|
7
|
+
|
|
8
8
|
from pulpcore.plugin.models import Artifact
|
|
9
9
|
from pulpcore.plugin.util import get_domain
|
|
10
|
-
|
|
10
|
+
|
|
11
|
+
from pulp_python.app.provenance import Attestation
|
|
12
|
+
from pulp_python.app.utils import DIST_EXTENSIONS, SUPPORTED_METADATA_VERSIONS
|
|
11
13
|
|
|
12
14
|
log = logging.getLogger(__name__)
|
|
13
15
|
|
|
@@ -110,7 +112,7 @@ class PackageUploadSerializer(serializers.Serializer):
|
|
|
110
112
|
attestations = TypeAdapter(list[Attestation]).validate_python(attestations)
|
|
111
113
|
except ValidationError as e:
|
|
112
114
|
raise serializers.ValidationError(
|
|
113
|
-
{"attestations": _("The uploaded attestations are not valid: {}".format(e)
|
|
115
|
+
{"attestations": _("The uploaded attestations are not valid: {}").format(e)}
|
|
114
116
|
)
|
|
115
117
|
|
|
116
118
|
sha256 = data.get("sha256_digest")
|
pulp_python/app/pypi/views.py
CHANGED
|
@@ -1,60 +1,61 @@
|
|
|
1
1
|
import logging
|
|
2
|
-
|
|
3
|
-
from
|
|
4
|
-
from
|
|
5
|
-
from
|
|
6
|
-
from rest_framework.exceptions import NotAcceptable
|
|
7
|
-
from django.core.exceptions import ObjectDoesNotExist
|
|
8
|
-
from django.shortcuts import redirect
|
|
9
|
-
from datetime import datetime, timezone, timedelta
|
|
2
|
+
from datetime import datetime, timedelta, timezone
|
|
3
|
+
from itertools import chain
|
|
4
|
+
from pathlib import PurePath
|
|
5
|
+
from urllib.parse import urljoin, urlparse, urlunsplit
|
|
10
6
|
|
|
11
7
|
from django.contrib.sessions.models import Session
|
|
8
|
+
from django.core.exceptions import ObjectDoesNotExist
|
|
12
9
|
from django.db import transaction
|
|
10
|
+
from django.db.models import OuterRef, Subquery
|
|
13
11
|
from django.db.utils import DatabaseError
|
|
14
12
|
from django.http.response import (
|
|
15
13
|
Http404,
|
|
16
|
-
|
|
17
|
-
HttpResponseForbidden,
|
|
14
|
+
HttpResponse,
|
|
18
15
|
HttpResponseBadRequest,
|
|
16
|
+
HttpResponseForbidden,
|
|
17
|
+
HttpResponseNotFound,
|
|
19
18
|
StreamingHttpResponse,
|
|
20
|
-
HttpResponse,
|
|
21
19
|
)
|
|
20
|
+
from django.shortcuts import redirect
|
|
22
21
|
from drf_spectacular.utils import extend_schema
|
|
23
22
|
from dynaconf import settings
|
|
24
|
-
from itertools import chain
|
|
25
23
|
from packaging.utils import canonicalize_name
|
|
26
|
-
from
|
|
27
|
-
from
|
|
24
|
+
from rest_framework.exceptions import NotAcceptable
|
|
25
|
+
from rest_framework.renderers import BrowsableAPIRenderer, JSONRenderer, TemplateHTMLRenderer
|
|
26
|
+
from rest_framework.response import Response
|
|
27
|
+
from rest_framework.viewsets import ViewSet
|
|
28
28
|
|
|
29
|
-
from pulpcore.plugin.
|
|
29
|
+
from pulpcore.plugin.models import RepositoryContent
|
|
30
30
|
from pulpcore.plugin.tasking import dispatch
|
|
31
31
|
from pulpcore.plugin.util import get_domain, get_url
|
|
32
|
+
from pulpcore.plugin.viewsets import OperationPostponedResponse
|
|
33
|
+
|
|
34
|
+
from pulp_python.app import tasks
|
|
32
35
|
from pulp_python.app.models import (
|
|
36
|
+
PackageProvenance,
|
|
33
37
|
PythonDistribution,
|
|
34
38
|
PythonPackageContent,
|
|
35
39
|
PythonPublication,
|
|
36
|
-
PackageProvenance,
|
|
37
40
|
)
|
|
38
41
|
from pulp_python.app.pypi.serializers import (
|
|
39
|
-
SummarySerializer,
|
|
40
42
|
PackageMetadataSerializer,
|
|
41
43
|
PackageUploadSerializer,
|
|
42
44
|
PackageUploadTaskSerializer,
|
|
45
|
+
SummarySerializer,
|
|
43
46
|
)
|
|
44
47
|
from pulp_python.app.utils import (
|
|
45
|
-
write_simple_index,
|
|
46
|
-
write_simple_index_json,
|
|
47
|
-
write_simple_detail,
|
|
48
|
-
write_simple_detail_json,
|
|
49
|
-
python_content_to_json,
|
|
50
48
|
PYPI_LAST_SERIAL,
|
|
51
49
|
PYPI_SERIAL_CONSTANT,
|
|
52
50
|
get_remote_package_filter,
|
|
53
51
|
get_remote_simple_page,
|
|
52
|
+
python_content_to_json,
|
|
53
|
+
write_simple_detail,
|
|
54
|
+
write_simple_detail_json,
|
|
55
|
+
write_simple_index,
|
|
56
|
+
write_simple_index_json,
|
|
54
57
|
)
|
|
55
58
|
|
|
56
|
-
from pulp_python.app import tasks
|
|
57
|
-
|
|
58
59
|
log = logging.getLogger(__name__)
|
|
59
60
|
|
|
60
61
|
ORIGIN_HOST = settings.CONTENT_ORIGIN if settings.CONTENT_ORIGIN else settings.PYPI_API_HOSTNAME
|
|
@@ -367,13 +368,20 @@ class SimpleView(PackageUploadMixin, ViewSet):
|
|
|
367
368
|
return redirect(urljoin(self.base_content_url, f"{path}/simple/{normalized}/"))
|
|
368
369
|
if content is not None:
|
|
369
370
|
local_packages = content.filter(name_normalized=normalized)
|
|
370
|
-
|
|
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
|
+
packages = local_packages.annotate(
|
|
377
|
+
repo_added_time=Subquery(repo_added_subquery)
|
|
378
|
+
).values(
|
|
371
379
|
"filename",
|
|
372
380
|
"sha256",
|
|
373
381
|
"metadata_sha256",
|
|
374
382
|
"requires_python",
|
|
375
383
|
"size",
|
|
376
|
-
"
|
|
384
|
+
"repo_added_time",
|
|
377
385
|
"version",
|
|
378
386
|
)
|
|
379
387
|
provenances = PackageProvenance.objects.filter(package__in=local_packages).values_list(
|
|
@@ -383,7 +391,7 @@ class SimpleView(PackageUploadMixin, ViewSet):
|
|
|
383
391
|
p["filename"]: {
|
|
384
392
|
**p,
|
|
385
393
|
"url": urljoin(self.base_content_url, f"{path}/{p['filename']}"),
|
|
386
|
-
"upload_time": p["
|
|
394
|
+
"upload_time": p["repo_added_time"],
|
|
387
395
|
"provenance": (
|
|
388
396
|
self.get_provenance_url(normalized, p["version"], p["filename"])
|
|
389
397
|
if p["filename"] in provenances
|
|
@@ -465,7 +473,11 @@ class MetadataView(PyPIMixin, ViewSet):
|
|
|
465
473
|
if settings.DOMAIN_ENABLED:
|
|
466
474
|
domain = get_domain()
|
|
467
475
|
json_body = python_content_to_json(
|
|
468
|
-
path,
|
|
476
|
+
path,
|
|
477
|
+
package_content,
|
|
478
|
+
version=version,
|
|
479
|
+
domain=domain,
|
|
480
|
+
repository_version=repo_ver,
|
|
469
481
|
)
|
|
470
482
|
if json_body:
|
|
471
483
|
return Response(data=json_body, headers=headers)
|
pulp_python/app/replica.py
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
from pulpcore.plugin.replica import Replicator
|
|
2
|
-
|
|
3
1
|
from pulp_glue.python.context import (
|
|
4
2
|
PulpPythonDistributionContext,
|
|
5
3
|
PulpPythonPublicationContext,
|
|
6
4
|
PulpPythonRepositoryContext,
|
|
7
5
|
)
|
|
6
|
+
|
|
7
|
+
from pulpcore.plugin.replica import Replicator
|
|
8
|
+
|
|
8
9
|
from pulp_python.app.models import PythonDistribution, PythonRemote, PythonRepository
|
|
9
10
|
from pulp_python.app.tasks import sync as python_sync
|
|
10
11
|
|
pulp_python/app/serializers.py
CHANGED
|
@@ -2,33 +2,34 @@ import logging
|
|
|
2
2
|
import os
|
|
3
3
|
import tempfile
|
|
4
4
|
from gettext import gettext as _
|
|
5
|
+
from urllib.parse import urljoin
|
|
6
|
+
|
|
5
7
|
from django.conf import settings
|
|
6
8
|
from django.db.utils import IntegrityError
|
|
7
9
|
from drf_spectacular.utils import extend_schema_serializer
|
|
8
10
|
from packaging.requirements import Requirement
|
|
9
|
-
from packaging.version import
|
|
10
|
-
from rest_framework import serializers
|
|
11
|
-
from pypi_attestations import AttestationError
|
|
11
|
+
from packaging.version import InvalidVersion, Version
|
|
12
12
|
from pydantic import TypeAdapter, ValidationError
|
|
13
|
-
from
|
|
13
|
+
from pypi_attestations import AttestationError
|
|
14
|
+
from rest_framework import serializers
|
|
14
15
|
|
|
15
16
|
from pulpcore.plugin import models as core_models
|
|
16
17
|
from pulpcore.plugin import serializers as core_serializers
|
|
17
|
-
from pulpcore.plugin.util import get_domain, get_prn,
|
|
18
|
+
from pulpcore.plugin.util import get_current_authenticated_user, get_domain, get_prn, reverse
|
|
18
19
|
|
|
19
20
|
from pulp_python.app import models as python_models
|
|
20
|
-
from pulp_python.app.utils import canonicalize_name
|
|
21
21
|
from pulp_python.app.provenance import (
|
|
22
|
+
AnyPublisher,
|
|
22
23
|
Attestation,
|
|
24
|
+
AttestationBundle,
|
|
23
25
|
Provenance,
|
|
24
26
|
verify_provenance,
|
|
25
|
-
AttestationBundle,
|
|
26
|
-
AnyPublisher,
|
|
27
27
|
)
|
|
28
28
|
from pulp_python.app.utils import (
|
|
29
29
|
DIST_EXTENSIONS,
|
|
30
30
|
artifact_to_metadata_artifact,
|
|
31
31
|
artifact_to_python_content_data,
|
|
32
|
+
canonicalize_name,
|
|
32
33
|
get_project_metadata_from_file,
|
|
33
34
|
parse_project_metadata,
|
|
34
35
|
)
|
|
@@ -238,7 +239,7 @@ class PythonPackageContentSerializer(core_serializers.SingleArtifactContentUploa
|
|
|
238
239
|
required=False,
|
|
239
240
|
allow_blank=True,
|
|
240
241
|
help_text=_(
|
|
241
|
-
"The maintainer's name at a minimum;
|
|
242
|
+
"The maintainer's name at a minimum; additional contact information may be provided."
|
|
242
243
|
),
|
|
243
244
|
)
|
|
244
245
|
maintainer_email = serializers.CharField(
|
|
@@ -387,7 +388,7 @@ class PythonPackageContentSerializer(core_serializers.SingleArtifactContentUploa
|
|
|
387
388
|
else:
|
|
388
389
|
attestations = TypeAdapter(list[Attestation]).validate_python(value)
|
|
389
390
|
except ValidationError as e:
|
|
390
|
-
raise serializers.ValidationError(_("Invalid attestations: {}".format(e))
|
|
391
|
+
raise serializers.ValidationError(_("Invalid attestations: {}").format(e))
|
|
391
392
|
return attestations
|
|
392
393
|
|
|
393
394
|
def handle_attestations(self, filename, sha256, attestations, offline=True):
|
|
@@ -400,7 +401,7 @@ class PythonPackageContentSerializer(core_serializers.SingleArtifactContentUploa
|
|
|
400
401
|
verify_provenance(filename, sha256, provenance, offline=offline)
|
|
401
402
|
except AttestationError as e:
|
|
402
403
|
raise serializers.ValidationError(
|
|
403
|
-
{"attestations": _("Attestations failed verification: {}".format(e)
|
|
404
|
+
{"attestations": _("Attestations failed verification: {}").format(e)}
|
|
404
405
|
)
|
|
405
406
|
return provenance.model_dump(mode="json")
|
|
406
407
|
|
|
@@ -655,13 +656,13 @@ class PackageProvenanceSerializer(core_serializers.NoArtifactContentUploadSerial
|
|
|
655
656
|
data["provenance"] = provenance.model_dump(mode="json")
|
|
656
657
|
except ValidationError as e:
|
|
657
658
|
raise serializers.ValidationError(
|
|
658
|
-
_("The uploaded provenance is not valid: {}".format(e)
|
|
659
|
+
_("The uploaded provenance is not valid: {}").format(e)
|
|
659
660
|
)
|
|
660
661
|
if data.pop("verify"):
|
|
661
662
|
try:
|
|
662
663
|
verify_provenance(data["package"].filename, data["package"].sha256, provenance)
|
|
663
664
|
except AttestationError as e:
|
|
664
|
-
raise serializers.ValidationError(_("Provenance verification failed: {}".format(e))
|
|
665
|
+
raise serializers.ValidationError(_("Provenance verification failed: {}").format(e))
|
|
665
666
|
return data
|
|
666
667
|
|
|
667
668
|
def retrieve(self, validated_data):
|
|
@@ -729,7 +730,7 @@ class PythonRemoteSerializer(core_serializers.RemoteSerializer):
|
|
|
729
730
|
package_types = MultipleChoiceArrayField(
|
|
730
731
|
required=False,
|
|
731
732
|
help_text=_(
|
|
732
|
-
"The package types to sync for Python content. Leave blank to get
|
|
733
|
+
"The package types to sync for Python content. Leave blank to get everypackage type."
|
|
733
734
|
),
|
|
734
735
|
choices=python_models.PACKAGE_TYPES,
|
|
735
736
|
default=list,
|
|
@@ -764,7 +765,7 @@ class PythonRemoteSerializer(core_serializers.RemoteSerializer):
|
|
|
764
765
|
Requirement(pkg)
|
|
765
766
|
except ValueError as ve:
|
|
766
767
|
raise serializers.ValidationError(
|
|
767
|
-
_("includes specifier {} is invalid. {}".format(pkg, ve)
|
|
768
|
+
_("includes specifier {} is invalid. {}").format(pkg, ve)
|
|
768
769
|
)
|
|
769
770
|
return value
|
|
770
771
|
|
|
@@ -775,7 +776,7 @@ class PythonRemoteSerializer(core_serializers.RemoteSerializer):
|
|
|
775
776
|
Requirement(pkg)
|
|
776
777
|
except ValueError as ve:
|
|
777
778
|
raise serializers.ValidationError(
|
|
778
|
-
_("excludes specifier {} is invalid. {}".format(pkg, ve)
|
|
779
|
+
_("excludes specifier {} is invalid. {}").format(pkg, ve)
|
|
779
780
|
)
|
|
780
781
|
return value
|
|
781
782
|
|
pulp_python/app/tasks/publish.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
from gettext import gettext as _
|
|
2
1
|
import logging
|
|
3
2
|
import os
|
|
3
|
+
from gettext import gettext as _
|
|
4
4
|
|
|
5
5
|
from django.core.files import File
|
|
6
6
|
from packaging.utils import canonicalize_name
|
|
@@ -10,7 +10,7 @@ from pulpcore.plugin.util import get_domain
|
|
|
10
10
|
|
|
11
11
|
from pulp_python.app import models as python_models
|
|
12
12
|
from pulp_python.app.serializers import PythonPublicationSerializer
|
|
13
|
-
from pulp_python.app.utils import
|
|
13
|
+
from pulp_python.app.utils import write_simple_detail, write_simple_index
|
|
14
14
|
|
|
15
15
|
log = logging.getLogger(__name__)
|
|
16
16
|
|
pulp_python/app/tasks/repair.py
CHANGED
|
@@ -7,6 +7,10 @@ from uuid import UUID
|
|
|
7
7
|
|
|
8
8
|
from django.db.models import Prefetch
|
|
9
9
|
from django.db.models.query import QuerySet
|
|
10
|
+
|
|
11
|
+
from pulpcore.plugin.models import ContentArtifact, ProgressReport
|
|
12
|
+
from pulpcore.plugin.util import get_domain
|
|
13
|
+
|
|
10
14
|
from pulp_python.app.models import PythonPackageContent, PythonRepository
|
|
11
15
|
from pulp_python.app.utils import (
|
|
12
16
|
artifact_to_python_content_data,
|
|
@@ -16,8 +20,6 @@ from pulp_python.app.utils import (
|
|
|
16
20
|
metadata_content_to_artifact,
|
|
17
21
|
parse_metadata,
|
|
18
22
|
)
|
|
19
|
-
from pulpcore.plugin.models import ContentArtifact, ProgressReport
|
|
20
|
-
from pulpcore.plugin.util import get_domain
|
|
21
23
|
|
|
22
24
|
log = logging.getLogger(__name__)
|
|
23
25
|
|
pulp_python/app/tasks/sync.py
CHANGED
|
@@ -1,11 +1,17 @@
|
|
|
1
|
-
import logging
|
|
2
1
|
import asyncio
|
|
3
|
-
|
|
4
|
-
from aiohttp import ClientResponseError, ClientError
|
|
5
|
-
from lxml.etree import LxmlError
|
|
6
|
-
from gettext import gettext as _
|
|
2
|
+
import logging
|
|
7
3
|
from functools import partial
|
|
4
|
+
from gettext import gettext as _
|
|
5
|
+
from urllib.parse import urljoin
|
|
8
6
|
|
|
7
|
+
from aiohttp import ClientError, ClientResponseError
|
|
8
|
+
from bandersnatch.configuration import BandersnatchConfig
|
|
9
|
+
from bandersnatch.master import Master
|
|
10
|
+
from bandersnatch.mirror import Mirror
|
|
11
|
+
from lxml.etree import LxmlError
|
|
12
|
+
from packaging.requirements import Requirement
|
|
13
|
+
from pypi_attestations import Provenance
|
|
14
|
+
from pypi_simple import IndexPage
|
|
9
15
|
from rest_framework import serializers
|
|
10
16
|
|
|
11
17
|
from pulpcore.plugin.download import HttpDownloader
|
|
@@ -18,19 +24,11 @@ from pulpcore.plugin.stages import (
|
|
|
18
24
|
)
|
|
19
25
|
|
|
20
26
|
from pulp_python.app.models import (
|
|
27
|
+
PackageProvenance,
|
|
21
28
|
PythonPackageContent,
|
|
22
29
|
PythonRemote,
|
|
23
|
-
PackageProvenance,
|
|
24
30
|
)
|
|
25
|
-
from pulp_python.app.utils import
|
|
26
|
-
from pypi_simple import IndexPage
|
|
27
|
-
from pypi_attestations import Provenance
|
|
28
|
-
|
|
29
|
-
from bandersnatch.mirror import Mirror
|
|
30
|
-
from bandersnatch.master import Master
|
|
31
|
-
from bandersnatch.configuration import BandersnatchConfig
|
|
32
|
-
from packaging.requirements import Requirement
|
|
33
|
-
from urllib.parse import urljoin
|
|
31
|
+
from pulp_python.app.utils import PYPI_LAST_SERIAL, aget_remote_simple_page, parse_metadata
|
|
34
32
|
|
|
35
33
|
logger = logging.getLogger(__name__)
|
|
36
34
|
|
pulp_python/app/tasks/upload.py
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
import time
|
|
2
|
-
|
|
3
2
|
from datetime import datetime, timezone
|
|
4
|
-
|
|
3
|
+
|
|
5
4
|
from django.contrib.sessions.models import Session
|
|
5
|
+
from django.db import transaction
|
|
6
6
|
from pydantic import TypeAdapter
|
|
7
|
-
from pulpcore.plugin.models import Artifact, CreatedResource, Content, ContentArtifact
|
|
8
|
-
from pulpcore.plugin.util import get_domain, get_current_authenticated_user, get_prn
|
|
9
7
|
|
|
10
|
-
from
|
|
8
|
+
from pulpcore.plugin.models import Artifact, Content, ContentArtifact, CreatedResource
|
|
9
|
+
from pulpcore.plugin.util import get_current_authenticated_user, get_domain, get_prn
|
|
10
|
+
|
|
11
|
+
from pulp_python.app.models import PackageProvenance, PythonPackageContent, PythonRepository
|
|
11
12
|
from pulp_python.app.provenance import (
|
|
13
|
+
AnyPublisher,
|
|
12
14
|
Attestation,
|
|
13
15
|
AttestationBundle,
|
|
14
|
-
AnyPublisher,
|
|
15
16
|
Provenance,
|
|
16
17
|
verify_provenance,
|
|
17
18
|
)
|
pulp_python/app/urls.py
CHANGED
|
@@ -2,11 +2,11 @@ from django.conf import settings
|
|
|
2
2
|
from django.urls import path
|
|
3
3
|
|
|
4
4
|
from pulp_python.app.pypi.views import (
|
|
5
|
-
SimpleView,
|
|
6
5
|
MetadataView,
|
|
6
|
+
ProvenanceView,
|
|
7
7
|
PyPIView,
|
|
8
|
+
SimpleView,
|
|
8
9
|
UploadView,
|
|
9
|
-
ProvenanceView,
|
|
10
10
|
)
|
|
11
11
|
|
|
12
12
|
if settings.DOMAIN_ENABLED:
|
pulp_python/app/utils.py
CHANGED
|
@@ -1,23 +1,26 @@
|
|
|
1
1
|
import hashlib
|
|
2
|
+
import json
|
|
2
3
|
import logging
|
|
3
|
-
import pkginfo
|
|
4
4
|
import re
|
|
5
5
|
import shutil
|
|
6
6
|
import tempfile
|
|
7
7
|
import zipfile
|
|
8
|
-
import json
|
|
9
|
-
from aiohttp.client_exceptions import ClientError
|
|
10
8
|
from collections import defaultdict
|
|
11
9
|
from datetime import timezone
|
|
10
|
+
|
|
11
|
+
import pkginfo
|
|
12
|
+
from aiohttp.client_exceptions import ClientError
|
|
12
13
|
from django.conf import settings
|
|
14
|
+
from django.db.models import OuterRef, Subquery
|
|
13
15
|
from django.db.utils import IntegrityError
|
|
14
16
|
from jinja2 import Template
|
|
15
|
-
from packaging.utils import canonicalize_name
|
|
16
17
|
from packaging.requirements import Requirement
|
|
17
|
-
from packaging.
|
|
18
|
+
from packaging.utils import canonicalize_name
|
|
19
|
+
from packaging.version import InvalidVersion, parse
|
|
18
20
|
from pypi_simple import ACCEPT_JSON_PREFERRED, ProjectPage
|
|
19
|
-
|
|
21
|
+
|
|
20
22
|
from pulpcore.plugin.exceptions import TimeoutException
|
|
23
|
+
from pulpcore.plugin.models import Artifact, Remote, RepositoryContent
|
|
21
24
|
from pulpcore.plugin.util import get_domain
|
|
22
25
|
|
|
23
26
|
log = logging.getLogger(__name__)
|
|
@@ -357,7 +360,9 @@ def fetch_json_release_metadata(name: str, version: str, remotes: set[Remote]) -
|
|
|
357
360
|
raise Exception(f"Failed to fetch {url} from any remote.")
|
|
358
361
|
|
|
359
362
|
|
|
360
|
-
def python_content_to_json(
|
|
363
|
+
def python_content_to_json(
|
|
364
|
+
base_path, content_query, version=None, domain=None, repository_version=None
|
|
365
|
+
):
|
|
361
366
|
"""
|
|
362
367
|
Converts a QuerySet of PythonPackageContent into the PyPi JSON format
|
|
363
368
|
https://www.python.org/dev/peps/pep-0566/
|
|
@@ -369,6 +374,13 @@ def python_content_to_json(base_path, content_query, version=None, domain=None):
|
|
|
369
374
|
|
|
370
375
|
Returns None if version is specified but not found within content_query
|
|
371
376
|
"""
|
|
377
|
+
if repository_version:
|
|
378
|
+
repo_added_subquery = RepositoryContent.objects.filter(
|
|
379
|
+
content_id=OuterRef("pk"),
|
|
380
|
+
repository=repository_version.repository,
|
|
381
|
+
version_removed=None,
|
|
382
|
+
).values("pulp_created")[:1]
|
|
383
|
+
content_query = content_query.annotate(repo_added_time=Subquery(repo_added_subquery))
|
|
372
384
|
full_metadata = {"last_serial": 0} # For now the serial field isn't supported by Pulp
|
|
373
385
|
latest_content = latest_content_version(content_query, version)
|
|
374
386
|
if not latest_content:
|
|
@@ -513,8 +525,10 @@ def python_content_to_download_info(content, base_path, domain=None):
|
|
|
513
525
|
"python_version": content.python_version,
|
|
514
526
|
"requires_python": content.requires_python or None,
|
|
515
527
|
"size": content.size,
|
|
516
|
-
"upload_time": str(content.pulp_created),
|
|
517
|
-
"upload_time_iso_8601": str(
|
|
528
|
+
"upload_time": str(getattr(content, "repo_added_time", None) or content.pulp_created),
|
|
529
|
+
"upload_time_iso_8601": str(
|
|
530
|
+
(getattr(content, "repo_added_time", None) or content.pulp_created).isoformat()
|
|
531
|
+
),
|
|
518
532
|
"url": url,
|
|
519
533
|
"yanked": False,
|
|
520
534
|
"yanked_reason": None,
|
pulp_python/app/viewsets.py
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
1
3
|
from bandersnatch.configuration import BandersnatchConfig
|
|
2
4
|
from django.db import transaction
|
|
3
5
|
from django_filters import CharFilter
|
|
4
6
|
from django_filters.rest_framework import filters as drf_filters
|
|
5
7
|
from drf_spectacular.utils import extend_schema, extend_schema_view
|
|
6
8
|
from packaging.utils import canonicalize_name
|
|
7
|
-
from pathlib import Path
|
|
8
9
|
from rest_framework import status
|
|
9
10
|
from rest_framework.decorators import action
|
|
10
11
|
from rest_framework.mixins import (
|
|
@@ -259,6 +260,7 @@ class PythonBlocklistEntryViewSet(
|
|
|
259
260
|
parent_lookup_kwargs = {"repository_pk": "repository__pk"}
|
|
260
261
|
serializer_class = python_serializers.PythonBlocklistEntrySerializer
|
|
261
262
|
queryset = python_models.PythonBlocklistEntry.objects.all()
|
|
263
|
+
filterset_fields = {"name": ["exact"], "version": ["exact"], "filename": ["exact"]}
|
|
262
264
|
ordering = ("-pulp_created",)
|
|
263
265
|
|
|
264
266
|
DEFAULT_ACCESS_POLICY = {
|
pulp_python/pytest_plugin.py
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
|
-
import pytest
|
|
2
|
-
import uuid
|
|
3
1
|
import subprocess
|
|
2
|
+
import uuid
|
|
3
|
+
|
|
4
|
+
import pytest
|
|
4
5
|
|
|
5
6
|
from pulpcore.tests.functional.utils import BindingsNamespace
|
|
7
|
+
|
|
6
8
|
from pulp_python.tests.functional.constants import (
|
|
7
|
-
PYTHON_FIXTURE_URL,
|
|
8
|
-
PYTHON_XS_PROJECT_SPECIFIER,
|
|
9
9
|
PYTHON_EGG_FILENAME,
|
|
10
|
-
PYTHON_URL,
|
|
11
10
|
PYTHON_EGG_URL,
|
|
12
|
-
|
|
11
|
+
PYTHON_FIXTURE_URL,
|
|
12
|
+
PYTHON_URL,
|
|
13
13
|
PYTHON_WHEEL_FILENAME,
|
|
14
|
+
PYTHON_WHEEL_URL,
|
|
15
|
+
PYTHON_XS_PROJECT_SPECIFIER,
|
|
14
16
|
)
|
|
15
17
|
|
|
16
18
|
# Bindings API Fixtures
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import pytest
|
|
2
1
|
import json
|
|
3
|
-
import requests
|
|
4
2
|
import shutil
|
|
5
3
|
import subprocess
|
|
6
4
|
from pathlib import Path
|
|
7
5
|
from urllib.parse import urljoin
|
|
8
6
|
|
|
7
|
+
import pytest
|
|
8
|
+
import requests
|
|
9
9
|
from pypi_simple import PyPISimple
|
|
10
10
|
|
|
11
11
|
from pulpcore.tests.functional.utils import PulpTaskError
|
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
import pytest
|
|
2
|
-
|
|
3
1
|
from urllib.parse import urljoin
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
4
|
from pypi_simple import PyPISimple
|
|
5
5
|
|
|
6
6
|
from pulpcore.tests.functional.utils import PulpTaskError
|
|
7
|
+
|
|
7
8
|
from pulp_python.tests.functional.constants import (
|
|
8
|
-
PYTHON_FIXTURES_URL,
|
|
9
|
-
PYTHON_PACKAGE_DATA,
|
|
10
9
|
PYTHON_EGG_FILENAME,
|
|
11
10
|
PYTHON_EGG_URL,
|
|
11
|
+
PYTHON_FIXTURES_URL,
|
|
12
|
+
PYTHON_PACKAGE_DATA,
|
|
12
13
|
PYTHON_SM_FIXTURE_CHECKSUMS,
|
|
13
14
|
PYTHON_WHEEL_FILENAME,
|
|
14
15
|
PYTHON_WHEEL_URL,
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import pytest
|
|
2
1
|
import random
|
|
3
|
-
from pypi_simple import PyPISimple
|
|
4
2
|
from urllib.parse import urljoin
|
|
5
3
|
|
|
4
|
+
import pytest
|
|
5
|
+
from pypi_simple import PyPISimple
|
|
6
|
+
|
|
6
7
|
from pulp_python.tests.functional.constants import (
|
|
7
|
-
PYTHON_SM_PROJECT_SPECIFIER,
|
|
8
|
-
PYTHON_SM_FIXTURE_RELEASES,
|
|
9
|
-
PYTHON_SM_FIXTURE_CHECKSUMS,
|
|
10
8
|
PYTHON_EGG_FILENAME,
|
|
9
|
+
PYTHON_SM_FIXTURE_CHECKSUMS,
|
|
10
|
+
PYTHON_SM_FIXTURE_RELEASES,
|
|
11
|
+
PYTHON_SM_PROJECT_SPECIFIER,
|
|
11
12
|
PYTHON_WHEEL_FILENAME,
|
|
12
13
|
)
|
|
13
14
|
from pulp_python.tests.functional.utils import ensure_simple
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import pytest
|
|
2
1
|
import uuid
|
|
3
2
|
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
4
5
|
from pulp_python.tests.functional.constants import (
|
|
5
6
|
BANDERSNATCH_CONF,
|
|
6
7
|
DEFAULT_BANDER_REMOTE_BODY,
|
|
7
|
-
PYTHON_INVALID_SPECIFIER_NO_NAME,
|
|
8
8
|
PYTHON_INVALID_SPECIFIER_BAD_VERSION,
|
|
9
|
+
PYTHON_INVALID_SPECIFIER_NO_NAME,
|
|
9
10
|
PYTHON_VALID_SPECIFIER_NO_VERSION,
|
|
10
11
|
)
|
|
11
12
|
|
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
import pytest
|
|
2
|
-
import uuid
|
|
3
1
|
import json
|
|
4
2
|
import subprocess
|
|
3
|
+
import uuid
|
|
4
|
+
from urllib.parse import urlsplit
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
import pytest
|
|
7
|
+
|
|
8
|
+
from pulpcore.app import settings # noqa: TID251
|
|
7
9
|
|
|
8
10
|
from pulp_python.tests.functional.constants import (
|
|
9
11
|
PYTHON_EGG_FILENAME,
|
|
10
|
-
PYTHON_SM_PROJECT_SPECIFIER,
|
|
11
12
|
PYTHON_SM_PACKAGE_COUNT,
|
|
13
|
+
PYTHON_SM_PROJECT_SPECIFIER,
|
|
12
14
|
)
|
|
13
|
-
from urllib.parse import urlsplit
|
|
14
15
|
|
|
15
16
|
pytestmark = pytest.mark.skipif(not settings.DOMAIN_ENABLED, reason="Domain not enabled")
|
|
16
17
|
|
|
@@ -5,13 +5,15 @@ NOTE: assumes ALLOWED_EXPORT_PATHS setting contains "/tmp" - all tests will fail
|
|
|
5
5
|
the case.
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
|
-
import pytest
|
|
9
8
|
import uuid
|
|
10
9
|
|
|
11
|
-
|
|
10
|
+
import pytest
|
|
11
|
+
|
|
12
|
+
from pulpcore.app import settings # noqa: TID251
|
|
13
|
+
|
|
12
14
|
from pulp_python.tests.functional.constants import (
|
|
13
|
-
PYTHON_XS_PROJECT_SPECIFIER,
|
|
14
15
|
PYTHON_SM_PROJECT_SPECIFIER,
|
|
16
|
+
PYTHON_XS_PROJECT_SPECIFIER,
|
|
15
17
|
)
|
|
16
18
|
|
|
17
19
|
pytestmark = [
|
|
@@ -1,20 +1,20 @@
|
|
|
1
|
+
import subprocess
|
|
2
|
+
from hashlib import sha256
|
|
3
|
+
from random import sample
|
|
4
|
+
from urllib.parse import urljoin, urlsplit, urlunsplit
|
|
5
|
+
|
|
1
6
|
import pytest
|
|
2
7
|
import requests
|
|
3
|
-
import
|
|
8
|
+
from packaging.version import parse
|
|
9
|
+
from pypi_simple import ProjectPage
|
|
4
10
|
|
|
5
11
|
from pulp_python.tests.functional.constants import (
|
|
6
12
|
PYPI_URL,
|
|
7
|
-
PYTHON_XS_FIXTURE_CHECKSUMS,
|
|
8
|
-
PYTHON_SM_PROJECT_SPECIFIER,
|
|
9
13
|
PYTHON_SM_FIXTURE_RELEASES,
|
|
14
|
+
PYTHON_SM_PROJECT_SPECIFIER,
|
|
15
|
+
PYTHON_XS_FIXTURE_CHECKSUMS,
|
|
10
16
|
)
|
|
11
17
|
|
|
12
|
-
from pypi_simple import ProjectPage
|
|
13
|
-
from packaging.version import parse
|
|
14
|
-
from urllib.parse import urljoin, urlsplit, urlunsplit
|
|
15
|
-
from random import sample
|
|
16
|
-
from hashlib import sha256
|
|
17
|
-
|
|
18
18
|
|
|
19
19
|
def test_pull_through_install(
|
|
20
20
|
python_bindings, python_remote_factory, python_distribution_factory, delete_orphans_pre
|
|
@@ -1,18 +1,23 @@
|
|
|
1
|
-
import pytest
|
|
2
|
-
import requests
|
|
3
1
|
import subprocess
|
|
4
|
-
|
|
2
|
+
import time
|
|
3
|
+
from datetime import datetime
|
|
5
4
|
from urllib.parse import urljoin
|
|
6
5
|
|
|
6
|
+
import pytest
|
|
7
|
+
import requests
|
|
8
|
+
|
|
7
9
|
from pulp_python.tests.functional.constants import (
|
|
8
10
|
PYPI_SERIAL_CONSTANT,
|
|
9
|
-
|
|
10
|
-
PYTHON_MD_PYPI_SUMMARY,
|
|
11
|
+
PYPI_SIMPLE_V1_JSON,
|
|
11
12
|
PYTHON_EGG_FILENAME,
|
|
12
13
|
PYTHON_EGG_SHA256,
|
|
14
|
+
PYTHON_MD_PROJECT_SPECIFIER,
|
|
15
|
+
PYTHON_MD_PYPI_SUMMARY,
|
|
13
16
|
PYTHON_WHEEL_FILENAME,
|
|
14
17
|
PYTHON_WHEEL_SHA256,
|
|
15
18
|
SHELF_PYTHON_JSON,
|
|
19
|
+
TWINE_WHEEL_FILENAME,
|
|
20
|
+
TWINE_WHEEL_URL,
|
|
16
21
|
)
|
|
17
22
|
from pulp_python.tests.functional.utils import ensure_metadata
|
|
18
23
|
|
|
@@ -328,3 +333,41 @@ def assert_download_info(expected, received, message="Failed to match"):
|
|
|
328
333
|
matched = True
|
|
329
334
|
break
|
|
330
335
|
assert matched is True, message
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
@pytest.mark.parallel
|
|
339
|
+
def test_upload_time_reflects_repo_addition(
|
|
340
|
+
monitor_task,
|
|
341
|
+
python_bindings,
|
|
342
|
+
python_content_factory,
|
|
343
|
+
python_distribution_factory,
|
|
344
|
+
python_repo_factory,
|
|
345
|
+
):
|
|
346
|
+
"""
|
|
347
|
+
Test that upload_time reflects repository addition time instead of content creation time.
|
|
348
|
+
Checks both Simple and JSON APIs.
|
|
349
|
+
"""
|
|
350
|
+
content = python_content_factory(TWINE_WHEEL_FILENAME, url=TWINE_WHEEL_URL)
|
|
351
|
+
content_created = datetime.fromisoformat(
|
|
352
|
+
str(python_bindings.ContentPackagesApi.read(content.pulp_href).pulp_created)
|
|
353
|
+
)
|
|
354
|
+
time.sleep(2)
|
|
355
|
+
|
|
356
|
+
repo = python_repo_factory()
|
|
357
|
+
body = {"add_content_units": [content.pulp_href]}
|
|
358
|
+
monitor_task(python_bindings.RepositoriesPythonApi.modify(repo.pulp_href, body).task)
|
|
359
|
+
distro = python_distribution_factory(repository=repo)
|
|
360
|
+
|
|
361
|
+
# Simple API
|
|
362
|
+
headers = {"Accept": PYPI_SIMPLE_V1_JSON}
|
|
363
|
+
resp = requests.get(f"{urljoin(distro.base_url, 'simple/')}twine", headers=headers)
|
|
364
|
+
assert resp.status_code == 200
|
|
365
|
+
simple_time = datetime.fromisoformat(resp.json()["files"][0]["upload-time"])
|
|
366
|
+
assert simple_time > content_created
|
|
367
|
+
|
|
368
|
+
# JSON API
|
|
369
|
+
json_resp = requests.get(urljoin(distro.base_url, "pypi/twine/json"))
|
|
370
|
+
assert json_resp.status_code == 200
|
|
371
|
+
json_time = datetime.fromisoformat(json_resp.json()["urls"][0]["upload_time"])
|
|
372
|
+
assert json_time > content_created
|
|
373
|
+
assert json_time == simple_time
|
|
@@ -5,6 +5,9 @@ import requests
|
|
|
5
5
|
|
|
6
6
|
from pulp_python.tests.functional.constants import (
|
|
7
7
|
PYPI_SERIAL_CONSTANT,
|
|
8
|
+
PYPI_SIMPLE_V1_HTML,
|
|
9
|
+
PYPI_SIMPLE_V1_JSON,
|
|
10
|
+
PYPI_TEXT_HTML,
|
|
8
11
|
PYTHON_SM_FIXTURE_CHECKSUMS,
|
|
9
12
|
PYTHON_SM_FIXTURE_RELEASES,
|
|
10
13
|
PYTHON_SM_PROJECT_SPECIFIER,
|
|
@@ -27,10 +30,6 @@ from pulp_python.tests.functional.utils import ensure_simple
|
|
|
27
30
|
|
|
28
31
|
API_VERSION = "1.1"
|
|
29
32
|
|
|
30
|
-
PYPI_TEXT_HTML = "text/html"
|
|
31
|
-
PYPI_SIMPLE_V1_HTML = "application/vnd.pypi.simple.v1+html"
|
|
32
|
-
PYPI_SIMPLE_V1_JSON = "application/vnd.pypi.simple.v1+json"
|
|
33
|
-
|
|
34
33
|
|
|
35
34
|
@pytest.mark.parallel
|
|
36
35
|
def test_simple_html_index_api(
|
|
@@ -69,7 +68,7 @@ def test_simple_html_detail_api(
|
|
|
69
68
|
monitor_task(python_bindings.RepositoriesPythonApi.modify(repo.pulp_href, body).task)
|
|
70
69
|
distro = python_distribution_factory(repository=repo)
|
|
71
70
|
|
|
72
|
-
url = f
|
|
71
|
+
url = f"{urljoin(distro.base_url, 'simple/')}twine"
|
|
73
72
|
headers = {"Accept": PYPI_SIMPLE_V1_HTML}
|
|
74
73
|
|
|
75
74
|
response = requests.get(url, headers=headers)
|
|
@@ -125,7 +124,7 @@ def test_simple_json_detail_api(
|
|
|
125
124
|
monitor_task(python_bindings.RepositoriesPythonApi.modify(repo.pulp_href, body).task)
|
|
126
125
|
distro = python_distribution_factory(repository=repo)
|
|
127
126
|
|
|
128
|
-
url = f
|
|
127
|
+
url = f"{urljoin(distro.base_url, 'simple/')}twine"
|
|
129
128
|
headers = {"Accept": PYPI_SIMPLE_V1_JSON}
|
|
130
129
|
|
|
131
130
|
response = requests.get(url, headers=headers)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import pytest
|
|
2
1
|
import uuid
|
|
3
2
|
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
4
5
|
from pulp_python.tests.functional.constants import (
|
|
5
6
|
PYTHON_EGG_FILENAME,
|
|
6
7
|
PYTHON_EGG_SHA256,
|
|
@@ -44,9 +45,9 @@ def try_action(python_bindings, monitor_task):
|
|
|
44
45
|
except python_bindings.module.ApiException as e:
|
|
45
46
|
assert e.status == outcome, f"{e}"
|
|
46
47
|
else:
|
|
47
|
-
assert (
|
|
48
|
-
|
|
49
|
-
)
|
|
48
|
+
assert status_code == outcome, (
|
|
49
|
+
f"User performed {action} when they shouldn't been able to"
|
|
50
|
+
)
|
|
50
51
|
return data
|
|
51
52
|
|
|
52
53
|
return _try_action
|
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
import pytest
|
|
2
2
|
|
|
3
3
|
from pulp_python.tests.functional.constants import (
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
PYTHON_XS_PROJECT_SPECIFIER,
|
|
9
|
-
PYTHON_MD_PROJECT_SPECIFIER,
|
|
4
|
+
DJANGO_LATEST_3,
|
|
5
|
+
PYTHON_LG_FIXTURE_COUNTS,
|
|
6
|
+
PYTHON_LG_PACKAGE_COUNT,
|
|
7
|
+
PYTHON_LG_PROJECT_SPECIFIER,
|
|
10
8
|
PYTHON_MD_PACKAGE_COUNT,
|
|
11
|
-
|
|
9
|
+
PYTHON_MD_PROJECT_SPECIFIER,
|
|
10
|
+
PYTHON_PRERELEASE_TEST_SPECIFIER,
|
|
12
11
|
PYTHON_SM_PACKAGE_COUNT,
|
|
12
|
+
PYTHON_SM_PROJECT_SPECIFIER,
|
|
13
13
|
PYTHON_UNAVAILABLE_PACKAGE_COUNT,
|
|
14
14
|
PYTHON_UNAVAILABLE_PROJECT_SPECIFIER,
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
PYTHON_WITH_PRERELEASE_COUNT,
|
|
16
|
+
PYTHON_WITHOUT_PRERELEASE_COUNT,
|
|
17
|
+
PYTHON_XS_PACKAGE_COUNT,
|
|
18
|
+
PYTHON_XS_PROJECT_SPECIFIER,
|
|
19
19
|
SCIPY_COUNTS,
|
|
20
20
|
)
|
|
21
21
|
from pulp_python.tests.functional.utils import ensure_metadata
|
|
@@ -1,16 +1,18 @@
|
|
|
1
|
+
from urllib.parse import urljoin
|
|
2
|
+
|
|
1
3
|
import pytest
|
|
2
4
|
import requests
|
|
5
|
+
|
|
3
6
|
from pulp_python.tests.functional.constants import (
|
|
4
7
|
PYTHON_EGG_FILENAME,
|
|
8
|
+
PYTHON_EGG_SHA256,
|
|
5
9
|
PYTHON_EGG_URL,
|
|
6
10
|
PYTHON_FIXTURES_URL,
|
|
7
11
|
PYTHON_WHEEL_FILENAME,
|
|
8
|
-
PYTHON_WHEEL_URL,
|
|
9
|
-
PYTHON_EGG_SHA256,
|
|
10
12
|
PYTHON_WHEEL_SHA256,
|
|
13
|
+
PYTHON_WHEEL_URL,
|
|
11
14
|
)
|
|
12
15
|
from pulp_python.tests.functional.utils import ensure_metadata
|
|
13
|
-
from urllib.parse import urljoin
|
|
14
16
|
|
|
15
17
|
|
|
16
18
|
@pytest.mark.parametrize(
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
pulp_python/__init__.py,sha256=GIuTLoBTc-07dSLJUh8xrZPRz8x-jJ61pfR0J1IjnzI,65
|
|
2
|
-
pulp_python/pytest_plugin.py,sha256=
|
|
3
|
-
pulp_python/app/__init__.py,sha256=
|
|
2
|
+
pulp_python/pytest_plugin.py,sha256=LNnLjOkeEu2X4gJi614bHVmbsHyEwooHYIeecr96Qy4,8606
|
|
3
|
+
pulp_python/app/__init__.py,sha256=kvIZAie_YepDZxtZCUo9YVSjAZXhIjWL7sq7aSI88L8,2490
|
|
4
4
|
pulp_python/app/global_access_conditions.py,sha256=MZJtyoVsr-4hRaty6mKDqh3caOHd5UKJjEWLV2crOLs,1080
|
|
5
|
-
pulp_python/app/modelresource.py,sha256=
|
|
6
|
-
pulp_python/app/models.py,sha256=
|
|
5
|
+
pulp_python/app/modelresource.py,sha256=4SFAdqk6lozi_cZz4uqDIqhqPAZF-7l5jJwPn-xGZFs,1249
|
|
6
|
+
pulp_python/app/models.py,sha256=Y7MDTl2nKz1dz2S4KQIQQ4oWcYgBA4TyDVxJGBYPHY4,17705
|
|
7
7
|
pulp_python/app/provenance.py,sha256=iyhkuNahHiTDK0Djrd4-PlgErA5SJVI0uQOIPj46tEI,2352
|
|
8
|
-
pulp_python/app/replica.py,sha256=
|
|
9
|
-
pulp_python/app/serializers.py,sha256=
|
|
8
|
+
pulp_python/app/replica.py,sha256=qiWRP7tM_v4yP_XLIQfumfGolru-Jt6ZA0KVb-9g2cA,1882
|
|
9
|
+
pulp_python/app/serializers.py,sha256=Wg83g7LE9Qkf1S7hkkvG2_EJUi7D12l8UyCA1wmwf-I,33819
|
|
10
10
|
pulp_python/app/settings.py,sha256=Cyc_p6U0HQjKpyrRL6JFrK3R7RMQJ9MAgNMJCfzPEiA,255
|
|
11
|
-
pulp_python/app/urls.py,sha256=
|
|
12
|
-
pulp_python/app/utils.py,sha256=
|
|
13
|
-
pulp_python/app/viewsets.py,sha256=
|
|
11
|
+
pulp_python/app/urls.py,sha256=M2xjQ0j47BwQVpi75QCa5eUnQDcroKv3Cee7UrQ3QcA,1387
|
|
12
|
+
pulp_python/app/utils.py,sha256=f9sCzZ58Sf7EBNqzBG0NBGtWE6gE2eIcnoSTAhdVIIg,27303
|
|
13
|
+
pulp_python/app/viewsets.py,sha256=EyeuNNvklB74tSyL4MRfTnh4a5KVv2kUPgmeTUd6oSY,34209
|
|
14
14
|
pulp_python/app/management/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
15
15
|
pulp_python/app/management/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
16
|
-
pulp_python/app/management/commands/repair-python-metadata.py,sha256=
|
|
16
|
+
pulp_python/app/management/commands/repair-python-metadata.py,sha256=knvTPcPwyfgCH0-KNNCK1Mj0mQKzXUdYEwo-v6F94XU,4548
|
|
17
17
|
pulp_python/app/migrations/0001_initial.py,sha256=xbEeZoLAUhdVrySf22Uz-e9Jm32rbY_HjxuNcEar6EE,6843
|
|
18
18
|
pulp_python/app/migrations/0001_squashed_0010_update_json_field.py,sha256=hFo1OD0JS_vn8bl49nF3Qz9QZBkVc5uDdNRnporvuyY,10455
|
|
19
19
|
pulp_python/app/migrations/0002_pythonpackagecontent_python_version.py,sha256=2WMNRVfjbkVfI_cTu8VNQRlPXK4n-JuFRsBZFcm04AE,427
|
|
@@ -39,47 +39,47 @@ pulp_python/app/migrations/0021_pythonrepository_upload_duplicate_filenames.py,s
|
|
|
39
39
|
pulp_python/app/migrations/0022_pythonblocklistentry.py,sha256=EbtjZuN65myTAHVWrJYbt4mWgWL7EElEYs1XulHB6Bo,1732
|
|
40
40
|
pulp_python/app/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
41
41
|
pulp_python/app/pypi/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
42
|
-
pulp_python/app/pypi/serializers.py,sha256=
|
|
43
|
-
pulp_python/app/pypi/views.py,sha256=
|
|
42
|
+
pulp_python/app/pypi/serializers.py,sha256=rE0Cci2IMg4NbNWlVdo-8zPaJCAUq2Re57q_T3jMt0Y,5030
|
|
43
|
+
pulp_python/app/pypi/views.py,sha256=D2lsHijKp3ZJemt-iwWxjJEin5rAkc0pZzi9kZyQgwk,21651
|
|
44
44
|
pulp_python/app/tasks/__init__.py,sha256=lTFpVvpDKbqv9RC0b2RYU8Bo6svDjrA-djt16pADFr8,284
|
|
45
|
-
pulp_python/app/tasks/publish.py,sha256=
|
|
46
|
-
pulp_python/app/tasks/repair.py,sha256=
|
|
47
|
-
pulp_python/app/tasks/sync.py,sha256=
|
|
48
|
-
pulp_python/app/tasks/upload.py,sha256=
|
|
45
|
+
pulp_python/app/tasks/publish.py,sha256=bjsJzqJbLu7TF5rLb-UsZMmlNnc_LKw-sdHX9Gcatbw,4334
|
|
46
|
+
pulp_python/app/tasks/repair.py,sha256=5InzdbjW8y3AC4Vj2PsNLm3wGGTr8D3LcfPw_WA2Fks,12257
|
|
47
|
+
pulp_python/app/tasks/sync.py,sha256=LqGQsiSbOQl05H9e7PC830aaLDuQXS1Ql1GiwfrO1Qc,12866
|
|
48
|
+
pulp_python/app/tasks/upload.py,sha256=Pclsh6co5hBO6wdxZbGKBUSBV643nd9c2RXQO2Nkdik,5698
|
|
49
49
|
pulp_python/app/tasks/vulnerability_report.py,sha256=0cyxNb4048HFUdUlGBA6wYsg-hEMjSfE8mtw05Ct9BQ,1126
|
|
50
50
|
pulp_python/app/webserver_snippets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
51
51
|
pulp_python/app/webserver_snippets/apache.conf,sha256=3frHSl2YV_8pJPscaFxMVo7HmxGJdb8XVmfdLtCxzoA,97
|
|
52
52
|
pulp_python/app/webserver_snippets/nginx.conf,sha256=gMqZGFefsTJVVx9YRxpHVS7NMEll9CzOseYdtLr3Avc,344
|
|
53
53
|
pulp_python/tests/__init__.py,sha256=4Yz43a8s-KyhdHFb5eEhIIvH72807Y84uAHnG5bO5y0,31
|
|
54
54
|
pulp_python/tests/functional/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
55
|
-
pulp_python/tests/functional/constants.py,sha256=
|
|
56
|
-
pulp_python/tests/functional/utils.py,sha256=
|
|
55
|
+
pulp_python/tests/functional/constants.py,sha256=4e_zssE9G1bSNNJxYo7VgwvojUL_NocG5mUH996KBJs,13969
|
|
56
|
+
pulp_python/tests/functional/utils.py,sha256=GWnXrsQGZd0Ngewa_9yce58Qc3z7FbrlRvqao_8ZML0,5901
|
|
57
57
|
pulp_python/tests/functional/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
58
|
-
pulp_python/tests/functional/api/test_attestations.py,sha256=
|
|
58
|
+
pulp_python/tests/functional/api/test_attestations.py,sha256=cyZl4jCL-Q5Qu7XpxLc5_YmCzyc1Ctfl1IvSJ6YPQQU,8640
|
|
59
59
|
pulp_python/tests/functional/api/test_auto_publish.py,sha256=uCIt4LsO61oMk3bDs3LMQDJI8zkKqvY0b1uX16bTxzM,1747
|
|
60
|
-
pulp_python/tests/functional/api/test_blocklist.py,sha256=
|
|
61
|
-
pulp_python/tests/functional/api/test_consume_content.py,sha256
|
|
62
|
-
pulp_python/tests/functional/api/test_crud_content_unit.py,sha256=
|
|
63
|
-
pulp_python/tests/functional/api/test_crud_publications.py,sha256=
|
|
64
|
-
pulp_python/tests/functional/api/test_crud_remotes.py,sha256=
|
|
65
|
-
pulp_python/tests/functional/api/test_domains.py,sha256=
|
|
66
|
-
pulp_python/tests/functional/api/test_download_content.py,sha256=
|
|
67
|
-
pulp_python/tests/functional/api/test_export_import.py,sha256=
|
|
68
|
-
pulp_python/tests/functional/api/test_full_mirror.py,sha256=
|
|
69
|
-
pulp_python/tests/functional/api/test_pypi_apis.py,sha256=
|
|
70
|
-
pulp_python/tests/functional/api/test_pypi_simple_api.py,sha256=
|
|
71
|
-
pulp_python/tests/functional/api/test_rbac.py,sha256
|
|
72
|
-
pulp_python/tests/functional/api/test_repair.py,sha256=
|
|
73
|
-
pulp_python/tests/functional/api/test_sync.py,sha256=
|
|
74
|
-
pulp_python/tests/functional/api/test_upload.py,sha256=
|
|
60
|
+
pulp_python/tests/functional/api/test_blocklist.py,sha256=IWzlazoQbrfyHNq9bNAa9FcbShWqzC2Zhq8qrN7HBwg,5994
|
|
61
|
+
pulp_python/tests/functional/api/test_consume_content.py,sha256=-7b6KOrIT3NLSUafeu1tzXEXRPddDbS5VeMHxMIy2n8,999
|
|
62
|
+
pulp_python/tests/functional/api/test_crud_content_unit.py,sha256=R5Gvl4ZjW1eQHmrbqsR0zfzKANBxEKwlr_lugHir7Kk,13794
|
|
63
|
+
pulp_python/tests/functional/api/test_crud_publications.py,sha256=3cuSDC9C9M1opt0lh5ObGj8t7gq5jUW-RWj6MrA4Teo,5647
|
|
64
|
+
pulp_python/tests/functional/api/test_crud_remotes.py,sha256=clFFhgG5udyKzWOLwxpmwjhiVz8r5JEPAQHkztcAf9w,5812
|
|
65
|
+
pulp_python/tests/functional/api/test_domains.py,sha256=BnWBwid_RA0xenBBHwvkT5_23RPe19DjQCICdMWad3w,10227
|
|
66
|
+
pulp_python/tests/functional/api/test_download_content.py,sha256=5IuaHXyLakPkjm5sLTxtTl7Dq0yl7N36HpObnIa0Sks,4950
|
|
67
|
+
pulp_python/tests/functional/api/test_export_import.py,sha256=rHns9wdaeP-vtfW_qoGHU9EVuJ4YuWE0-rjl_8otAgU,4530
|
|
68
|
+
pulp_python/tests/functional/api/test_full_mirror.py,sha256=eU5HzgBBFOnX1q4m8ELx-t-I3U4TWXL-LNrlc2BcWVc,12045
|
|
69
|
+
pulp_python/tests/functional/api/test_pypi_apis.py,sha256=mhST0GV-uDrVPsBWYRGaJx1pp9htzbYiUGuIGOI0s_s,13218
|
|
70
|
+
pulp_python/tests/functional/api/test_pypi_simple_api.py,sha256=tOUl8WXgJkMoxGyLbA-WorCxIRKfGWM-27_dK_Jc0Q4,7171
|
|
71
|
+
pulp_python/tests/functional/api/test_rbac.py,sha256=-xNWqvKKU-v1uC6tCRGBK0aWaff25K9C-AfzQkdHhhI,10513
|
|
72
|
+
pulp_python/tests/functional/api/test_repair.py,sha256=4FR7jx_LA2K-pnRJXKkhq-1uUoWXST1leZ9XdyhGM2U,12909
|
|
73
|
+
pulp_python/tests/functional/api/test_sync.py,sha256=TTHR1CpZeRoD97RKxj2pZPsP0OS9ibYKGPOh1WfKISg,13801
|
|
74
|
+
pulp_python/tests/functional/api/test_upload.py,sha256=PZ0HK7UU9gvxNaRlB_EAY1-pcghDtx22DMGk5C1oM2I,5879
|
|
75
75
|
pulp_python/tests/functional/api/test_vulnerability_report.py,sha256=Rv492Wrvu1FY7O_moo9DTB6OkI-OZURj_fuTKbENLh8,1730
|
|
76
76
|
pulp_python/tests/functional/assets/shelf-reader-0.1.tar.gz.publish.attestation,sha256=_Ygrz7523z55s4uPmQWYxF29jr0NqJxVm_d-Z8KvrZ0,10363
|
|
77
77
|
pulp_python/tests/functional/assets/shelf_reader-0.1-py2-none-any.whl.publish.attestation,sha256=muTQ8dqYSSdx76DlaPjB1REcNIS-aak-Na0TkASxu8M,10426
|
|
78
78
|
pulp_python/tests/unit/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
79
79
|
pulp_python/tests/unit/test_models.py,sha256=TBI0yKsrdbnJSPeBFfxSqhXK7zaNvR6qg5JehGH3Pds,229
|
|
80
|
-
pulp_python-3.
|
|
81
|
-
pulp_python-3.
|
|
82
|
-
pulp_python-3.
|
|
83
|
-
pulp_python-3.
|
|
84
|
-
pulp_python-3.
|
|
85
|
-
pulp_python-3.
|
|
80
|
+
pulp_python-3.30.1.dist-info/licenses/LICENSE,sha256=2ylvL381vKOhdO-w6zkrOxe9lLNBhRQpo9_0EbHC_HM,18046
|
|
81
|
+
pulp_python-3.30.1.dist-info/METADATA,sha256=BcaJBgi3HQekc7OK4Ub3IBxMf5q42FQJDfnfRvQbevY,1744
|
|
82
|
+
pulp_python-3.30.1.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
83
|
+
pulp_python-3.30.1.dist-info/entry_points.txt,sha256=HvqLEXjw_dS5jqAwnE5JiRZFE6f-y5SRtitKLPml2To,115
|
|
84
|
+
pulp_python-3.30.1.dist-info/top_level.txt,sha256=X0hXgXc_bpbiKqVrkt8jD5_QEiQviKbHDwveQcOcJjo,12
|
|
85
|
+
pulp_python-3.30.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|