pulp-python 3.28.2__tar.gz → 3.30.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.
Files changed (97) hide show
  1. {pulp_python-3.28.2 → pulp_python-3.30.0}/CHANGES.md +85 -0
  2. {pulp_python-3.28.2 → pulp_python-3.30.0}/PKG-INFO +1 -1
  3. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/app/__init__.py +5 -3
  4. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/app/management/commands/repair-python-metadata.py +7 -3
  5. pulp_python-3.30.0/pulp_python/app/migrations/0022_pythonblocklistentry.py +48 -0
  6. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/app/modelresource.py +1 -0
  7. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/app/models.py +78 -12
  8. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/app/pypi/serializers.py +7 -5
  9. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/app/pypi/views.py +23 -24
  10. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/app/replica.py +3 -2
  11. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/app/serializers.py +136 -14
  12. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/app/tasks/publish.py +2 -2
  13. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/app/tasks/repair.py +4 -2
  14. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/app/tasks/sync.py +13 -15
  15. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/app/tasks/upload.py +7 -6
  16. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/app/utils.py +8 -6
  17. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/app/viewsets.py +81 -3
  18. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/pytest_plugin.py +8 -6
  19. pulp_python-3.30.0/pulp_python/tests/functional/api/test_blocklist.py +152 -0
  20. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/tests/functional/api/test_consume_content.py +0 -1
  21. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/tests/functional/api/test_crud_content_unit.py +5 -4
  22. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/tests/functional/api/test_crud_publications.py +6 -5
  23. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/tests/functional/api/test_crud_remotes.py +3 -2
  24. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/tests/functional/api/test_domains.py +6 -5
  25. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/tests/functional/api/test_export_import.py +5 -3
  26. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/tests/functional/api/test_pypi_simple_api.py +2 -2
  27. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/tests/functional/api/test_rbac.py +5 -4
  28. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/tests/functional/api/test_repair.py +2 -1
  29. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/tests/functional/api/test_upload.py +5 -3
  30. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python.egg-info/PKG-INFO +1 -1
  31. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python.egg-info/SOURCES.txt +2 -0
  32. {pulp_python-3.28.2 → pulp_python-3.30.0}/pyproject.toml +31 -2
  33. {pulp_python-3.28.2 → pulp_python-3.30.0}/COMMITMENT +0 -0
  34. {pulp_python-3.28.2 → pulp_python-3.30.0}/COPYRIGHT +0 -0
  35. {pulp_python-3.28.2 → pulp_python-3.30.0}/LICENSE +0 -0
  36. {pulp_python-3.28.2 → pulp_python-3.30.0}/MANIFEST.in +0 -0
  37. {pulp_python-3.28.2 → pulp_python-3.30.0}/README.md +0 -0
  38. {pulp_python-3.28.2 → pulp_python-3.30.0}/functest_requirements.txt +0 -0
  39. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/__init__.py +0 -0
  40. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/app/global_access_conditions.py +0 -0
  41. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/app/management/__init__.py +0 -0
  42. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/app/management/commands/__init__.py +0 -0
  43. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/app/migrations/0001_initial.py +0 -0
  44. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/app/migrations/0001_squashed_0010_update_json_field.py +0 -0
  45. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/app/migrations/0002_pythonpackagecontent_python_version.py +0 -0
  46. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/app/migrations/0003_new_sync_filters.py +0 -0
  47. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/app/migrations/0004_DATA_swap_distribution_model.py +0 -0
  48. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/app/migrations/0005_pythonpackagecontent_sha256.py +0 -0
  49. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/app/migrations/0006_pythonrepository_autopublish.py +0 -0
  50. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/app/migrations/0007_pythonpackagecontent_mv-2-1.py +0 -0
  51. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/app/migrations/0008_pythonpackagecontent_unique_sha256.py +0 -0
  52. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/app/migrations/0009_pythondistribution_allow_uploads.py +0 -0
  53. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/app/migrations/0010_update_json_field.py +0 -0
  54. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/app/migrations/0011_alter_pythondistribution_distribution_ptr_and_more.py +0 -0
  55. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/app/migrations/0012_add_domain.py +0 -0
  56. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/app/migrations/0013_add_rbac_permissions.py +0 -0
  57. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/app/migrations/0014_pythonpackagecontent_dynamic_and_more.py +0 -0
  58. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/app/migrations/0015_alter_pythonpackagecontent_options.py +0 -0
  59. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/app/migrations/0016_pythonpackagecontent_metadata_sha256.py +0 -0
  60. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/app/migrations/0017_pythonpackagecontent_size.py +0 -0
  61. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/app/migrations/0018_packageprovenance.py +0 -0
  62. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/app/migrations/0019_create_missing_metadata_artifacts.py +0 -0
  63. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/app/migrations/0020_pythonpackagecontent_name_normalized.py +0 -0
  64. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/app/migrations/0021_pythonrepository_upload_duplicate_filenames.py +0 -0
  65. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/app/migrations/__init__.py +0 -0
  66. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/app/provenance.py +0 -0
  67. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/app/pypi/__init__.py +0 -0
  68. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/app/settings.py +0 -0
  69. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/app/tasks/__init__.py +0 -0
  70. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/app/tasks/vulnerability_report.py +0 -0
  71. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/app/urls.py +2 -2
  72. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/app/webserver_snippets/__init__.py +0 -0
  73. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/app/webserver_snippets/apache.conf +0 -0
  74. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/app/webserver_snippets/nginx.conf +0 -0
  75. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/tests/__init__.py +0 -0
  76. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/tests/functional/__init__.py +0 -0
  77. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/tests/functional/api/__init__.py +0 -0
  78. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/tests/functional/api/test_attestations.py +2 -2
  79. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/tests/functional/api/test_auto_publish.py +0 -0
  80. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/tests/functional/api/test_download_content.py +2 -2
  81. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/tests/functional/api/test_full_mirror.py +9 -9
  82. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/tests/functional/api/test_pypi_apis.py +5 -5
  83. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/tests/functional/api/test_sync.py +11 -11
  84. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/tests/functional/api/test_vulnerability_report.py +0 -0
  85. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/tests/functional/assets/shelf-reader-0.1.tar.gz.publish.attestation +0 -0
  86. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/tests/functional/assets/shelf_reader-0.1-py2-none-any.whl.publish.attestation +0 -0
  87. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/tests/functional/constants.py +0 -0
  88. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/tests/functional/utils.py +2 -2
  89. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/tests/unit/__init__.py +0 -0
  90. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python/tests/unit/test_models.py +0 -0
  91. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python.egg-info/dependency_links.txt +0 -0
  92. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python.egg-info/entry_points.txt +0 -0
  93. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python.egg-info/requires.txt +0 -0
  94. {pulp_python-3.28.2 → pulp_python-3.30.0}/pulp_python.egg-info/top_level.txt +0 -0
  95. {pulp_python-3.28.2 → pulp_python-3.30.0}/setup.cfg +0 -0
  96. {pulp_python-3.28.2 → pulp_python-3.30.0}/test_requirements.txt +0 -0
  97. {pulp_python-3.28.2 → pulp_python-3.30.0}/unittest_requirements.txt +0 -0
@@ -8,6 +8,35 @@
8
8
 
9
9
  [//]: # (towncrier release notes start)
10
10
 
11
+ ## 3.30.0 (2026-05-13) {: #3.30.0 }
12
+
13
+ #### Features {: #3.30.0-feature }
14
+
15
+ - Added filtering by `name`, `version`, and `filename` to the blocklist entries API endpoint.
16
+ [#1229](https://github.com/pulp/pulp_python/issues/1229)
17
+
18
+ #### Deprecations and Removals {: #3.30.0-removal }
19
+
20
+ - Deprecated the `repair-python-metadata` management command in favor of the repository `repair_metadata` task.
21
+ [#1207](https://github.com/pulp/pulp_python/issues/1207)
22
+
23
+ ---
24
+
25
+ ## 3.29.0 (2026-04-17) {: #3.29.0 }
26
+
27
+ #### Features {: #3.29.0-feature }
28
+
29
+ - Added repository-specific package blocklist.
30
+ [#1166](https://github.com/pulp/pulp_python/issues/1166)
31
+
32
+ #### Bugfixes {: #3.29.0-bugfix }
33
+
34
+ - Fixed "Worker has gone missing" errors during repair_metadata on large repositories (1000+ packages) by reducing peak memory consumption.
35
+ [#1188](https://github.com/pulp/pulp_python/issues/1188)
36
+ - Support "atomic" replications in pulpcore 3.107
37
+
38
+ ---
39
+
11
40
  ## 3.28.2 (2026-04-14) {: #3.28.2 }
12
41
 
13
42
  #### Bugfixes {: #3.28.2-bugfix }
@@ -42,6 +71,23 @@
42
71
 
43
72
  ---
44
73
 
74
+ ## 3.27.2 (2026-04-14) {: #3.27.2 }
75
+
76
+ #### Bugfixes {: #3.27.2-bugfix }
77
+
78
+ - Fixed "Worker has gone missing" errors during repair_metadata on large repositories (1000+ packages) by reducing peak memory consumption.
79
+ [#1188](https://github.com/pulp/pulp_python/issues/1188)
80
+
81
+ ---
82
+
83
+ ## 3.27.1 (2026-04-01) {: #3.27.1 }
84
+
85
+ #### Bugfixes {: #3.27.1-bugfix }
86
+
87
+ - Support "atomic" replications in pulpcore 3.107
88
+
89
+ ---
90
+
45
91
  ## 3.27.0 (2026-03-17) {: #3.27.0 }
46
92
 
47
93
  #### Bugfixes {: #3.27.0-bugfix }
@@ -243,6 +289,23 @@
243
289
 
244
290
  ---
245
291
 
292
+ ## 3.19.3 (2026-05-04) {: #3.19.3 }
293
+
294
+ #### Bugfixes {: #3.19.3-bugfix }
295
+
296
+ - Fixed pull-through caching not checking the repository if package was not present on remote.
297
+ [#1004](https://github.com/pulp/pulp_python/issues/1004)
298
+ - Fixed pull-through caching failing for packages with bad names.
299
+ [#1040](https://github.com/pulp/pulp_python/issues/1040)
300
+
301
+ ---
302
+
303
+ ## 3.19.2 (2026-04-28) {: #3.19.2 }
304
+
305
+ No significant changes.
306
+
307
+ ---
308
+
246
309
  ## 3.19.1 (2025-09-14) {: #3.19.1 }
247
310
 
248
311
  #### Bugfixes {: #3.19.1-bugfix }
@@ -349,6 +412,14 @@
349
412
 
350
413
  ---
351
414
 
415
+ ## 3.13.6 (2026-04-01) {: #3.13.6 }
416
+
417
+ #### Bugfixes {: #3.13.6-bugfix }
418
+
419
+ - Support "atomic" replications in pulpcore 3.107
420
+
421
+ ---
422
+
352
423
  ## 3.13.5 (2025-04-23) {: #3.13.5 }
353
424
 
354
425
  No significant changes.
@@ -415,6 +486,14 @@ No significant changes.
415
486
 
416
487
  ---
417
488
 
489
+ ## 3.12.9 (2026-04-01) {: #3.12.9 }
490
+
491
+ #### Bugfixes {: #3.12.9-bugfix }
492
+
493
+ - Support "atomic" replications in pulpcore 3.107
494
+
495
+ ---
496
+
418
497
  ## 3.12.8 (2025-11-18) {: #3.12.8 }
419
498
 
420
499
  No significant changes.
@@ -507,6 +586,12 @@ No significant changes.
507
586
 
508
587
  ---
509
588
 
589
+ ## 3.11.8 (2026-04-21) {: #3.11.8 }
590
+
591
+ No significant changes.
592
+
593
+ ---
594
+
510
595
  ## 3.11.7 (2025-11-18) {: #3.11.7 }
511
596
 
512
597
  No significant changes.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pulp-python
3
- Version: 3.28.2
3
+ Version: 3.30.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
@@ -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.28.2"
15
+ version = "3.30.0"
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, MetadataView
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
- from django.core.management import BaseCommand, CommandError
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 = _("Repair the metadata of PythonPackageContent stored in PythonRepositories")
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."""
@@ -0,0 +1,48 @@
1
+ # Generated by Django 5.2.10 on 2026-04-16 14:00
2
+
3
+ import django.db.models.deletion
4
+ import django_lifecycle.mixins
5
+ import pulpcore.app.models.base
6
+ from django.db import migrations, models
7
+
8
+
9
+ class Migration(migrations.Migration):
10
+
11
+ dependencies = [
12
+ ("python", "0021_pythonrepository_upload_duplicate_filenames"),
13
+ ]
14
+
15
+ operations = [
16
+ migrations.CreateModel(
17
+ name="PythonBlocklistEntry",
18
+ fields=[
19
+ (
20
+ "pulp_id",
21
+ models.UUIDField(
22
+ default=pulpcore.app.models.base.pulp_uuid,
23
+ editable=False,
24
+ primary_key=True,
25
+ serialize=False,
26
+ ),
27
+ ),
28
+ ("pulp_created", models.DateTimeField(auto_now_add=True)),
29
+ ("pulp_last_updated", models.DateTimeField(auto_now=True, null=True)),
30
+ ("name", models.TextField(default=None, null=True)),
31
+ ("version", models.TextField(default=None, null=True)),
32
+ ("filename", models.TextField(default=None, null=True)),
33
+ ("added_by", models.TextField(default="")),
34
+ (
35
+ "repository",
36
+ models.ForeignKey(
37
+ on_delete=django.db.models.deletion.CASCADE,
38
+ related_name="blocklist_entries",
39
+ to="python.pythonrepository",
40
+ ),
41
+ ),
42
+ ],
43
+ options={
44
+ "default_related_name": "%(app_label)s_%(model_name)s",
45
+ },
46
+ bases=(django_lifecycle.mixins.LifecycleModelMixin, models.Model),
47
+ ),
48
+ ]
@@ -1,6 +1,7 @@
1
1
  from pulpcore.plugin.importexport import BaseContentResource
2
2
  from pulpcore.plugin.modelresources import RepositoryResource
3
3
  from pulpcore.plugin.util import get_domain
4
+
4
5
  from pulp_python.app.models import (
5
6
  PythonPackageContent,
6
7
  PythonRepository,
@@ -1,43 +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,
19
+ BaseModel,
17
20
  Content,
18
- Publication,
19
21
  Distribution,
22
+ Publication,
20
23
  Remote,
21
24
  Repository,
22
25
  )
26
+ from pulpcore.plugin.repo_version_utils import (
27
+ collect_duplicates,
28
+ remove_duplicates,
29
+ validate_repo_version,
30
+ )
23
31
  from pulpcore.plugin.responses import ArtifactResponse
32
+ from pulpcore.plugin.util import get_domain, get_domain_pk
24
33
 
25
- from pathlib import PurePath
26
34
  from .provenance import Provenance
27
35
  from .utils import (
28
- artifact_to_python_content_data,
36
+ PYPI_LAST_SERIAL,
37
+ PYPI_SERIAL_CONSTANT,
29
38
  artifact_to_metadata_artifact,
39
+ artifact_to_python_content_data,
30
40
  canonicalize_name,
31
41
  python_content_to_json,
32
- PYPI_LAST_SERIAL,
33
- PYPI_SERIAL_CONSTANT,
34
- )
35
- from pulpcore.plugin.repo_version_utils import (
36
- collect_duplicates,
37
- remove_duplicates,
38
- validate_repo_version,
39
42
  )
40
- from pulpcore.plugin.util import get_domain_pk, get_domain
41
43
 
42
44
  log = getLogger(__name__)
43
45
 
@@ -399,9 +401,12 @@ class PythonRepository(Repository, AutoAddObjPermsMixin):
399
401
 
400
402
  When allow_package_substitution is False, reject any new version that would implicitly
401
403
  replace existing content with different checksums (content substitution).
404
+
405
+ Also checks newly added content against the repository's blocklist entries.
402
406
  """
403
407
  if not self.allow_package_substitution:
404
408
  self._check_for_package_substitution(new_version)
409
+ self._check_blocklist(new_version)
405
410
  remove_duplicates(new_version)
406
411
  validate_repo_version(new_version)
407
412
 
@@ -418,3 +423,64 @@ class PythonRepository(Repository, AutoAddObjPermsMixin):
418
423
  "To allow this, set 'allow_package_substitution' to True on the repository. "
419
424
  f"Conflicting packages: {duplicates}"
420
425
  )
426
+
427
+ def _check_blocklist(self, new_version):
428
+ """
429
+ Check newly added content in a repository version against the blocklist.
430
+ """
431
+ added_content = PythonPackageContent.objects.filter(
432
+ pk__in=new_version.added().values_list("pk", flat=True)
433
+ ).only("filename", "name_normalized", "version")
434
+ if added_content.exists():
435
+ self.check_blocklist_for_packages(added_content)
436
+
437
+ def check_blocklist_for_packages(self, packages):
438
+ """
439
+ Raise a ValidationError if any of the given packages match a blocklist entry.
440
+ """
441
+ entries = PythonBlocklistEntry.objects.filter(repository=self)
442
+ if not entries.exists():
443
+ return
444
+
445
+ blocked = []
446
+ for pkg in packages:
447
+ for entry in entries:
448
+ if entry.filename and entry.filename == pkg.filename:
449
+ blocked.append(pkg.filename)
450
+ break
451
+ if entry.name == pkg.name_normalized:
452
+ if not entry.version or entry.version == pkg.version:
453
+ blocked.append(pkg.filename)
454
+ break
455
+ if blocked:
456
+ raise ValidationError(
457
+ "Blocklisted packages cannot be added to this repository: {}".format(
458
+ ", ".join(blocked)
459
+ )
460
+ )
461
+
462
+
463
+ class PythonBlocklistEntry(BaseModel):
464
+ """
465
+ An entry in a PythonRepository's package blocklist.
466
+
467
+ Blocklist entries prevent packages from being added to the repository.
468
+ Entries can match by package `name` (all versions), package `name` + `version`,
469
+ or exact `filename`. Exactly one of `name` or `filename` must be provided.
470
+ """
471
+
472
+ name = models.TextField(null=True, default=None)
473
+ version = models.TextField(null=True, default=None)
474
+ filename = models.TextField(null=True, default=None)
475
+ added_by = models.TextField(default="")
476
+ repository = models.ForeignKey(
477
+ PythonRepository, on_delete=models.CASCADE, related_name="blocklist_entries"
478
+ )
479
+
480
+ def __str__(self):
481
+ if self.filename:
482
+ return f"<{self._meta.object_name}: {self.filename}>"
483
+ return f"<{self._meta.object_name}: {self.name} [{self.version or 'all'}]>"
484
+
485
+ class Meta:
486
+ default_related_name = "%(app_label)s_%(model_name)s"
@@ -1,13 +1,15 @@
1
1
  import logging
2
2
  from gettext import gettext as _
3
3
 
4
- from rest_framework import serializers
4
+ from django.db.utils import IntegrityError
5
5
  from pydantic import TypeAdapter, ValidationError
6
- from pulp_python.app.provenance import Attestation
7
- from pulp_python.app.utils import DIST_EXTENSIONS, SUPPORTED_METADATA_VERSIONS
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
- from django.db.utils import IntegrityError
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")
@@ -1,60 +1,59 @@
1
1
  import logging
2
-
3
- from rest_framework.viewsets import ViewSet
4
- from rest_framework.renderers import BrowsableAPIRenderer, JSONRenderer, TemplateHTMLRenderer
5
- from rest_framework.response import Response
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
13
10
  from django.db.utils import DatabaseError
14
11
  from django.http.response import (
15
12
  Http404,
16
- HttpResponseNotFound,
17
- HttpResponseForbidden,
13
+ HttpResponse,
18
14
  HttpResponseBadRequest,
15
+ HttpResponseForbidden,
16
+ HttpResponseNotFound,
19
17
  StreamingHttpResponse,
20
- HttpResponse,
21
18
  )
19
+ from django.shortcuts import redirect
22
20
  from drf_spectacular.utils import extend_schema
23
21
  from dynaconf import settings
24
- from itertools import chain
25
22
  from packaging.utils import canonicalize_name
26
- from urllib.parse import urljoin, urlparse, urlunsplit
27
- from pathlib import PurePath
23
+ from rest_framework.exceptions import NotAcceptable
24
+ from rest_framework.renderers import BrowsableAPIRenderer, JSONRenderer, TemplateHTMLRenderer
25
+ from rest_framework.response import Response
26
+ from rest_framework.viewsets import ViewSet
28
27
 
29
- from pulpcore.plugin.viewsets import OperationPostponedResponse
30
28
  from pulpcore.plugin.tasking import dispatch
31
29
  from pulpcore.plugin.util import get_domain, get_url
30
+ from pulpcore.plugin.viewsets import OperationPostponedResponse
31
+
32
+ from pulp_python.app import tasks
32
33
  from pulp_python.app.models import (
34
+ PackageProvenance,
33
35
  PythonDistribution,
34
36
  PythonPackageContent,
35
37
  PythonPublication,
36
- PackageProvenance,
37
38
  )
38
39
  from pulp_python.app.pypi.serializers import (
39
- SummarySerializer,
40
40
  PackageMetadataSerializer,
41
41
  PackageUploadSerializer,
42
42
  PackageUploadTaskSerializer,
43
+ SummarySerializer,
43
44
  )
44
45
  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
46
  PYPI_LAST_SERIAL,
51
47
  PYPI_SERIAL_CONSTANT,
52
48
  get_remote_package_filter,
53
49
  get_remote_simple_page,
50
+ python_content_to_json,
51
+ write_simple_detail,
52
+ write_simple_detail_json,
53
+ write_simple_index,
54
+ write_simple_index_json,
54
55
  )
55
56
 
56
- from pulp_python.app import tasks
57
-
58
57
  log = logging.getLogger(__name__)
59
58
 
60
59
  ORIGIN_HOST = settings.CONTENT_ORIGIN if settings.CONTENT_ORIGIN else settings.PYPI_API_HOSTNAME
@@ -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