pulpcore 3.84.0__py3-none-any.whl → 3.85.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.

Potentially problematic release.


This version of pulpcore might be problematic. Click here for more details.

Files changed (163) hide show
  1. pulp_certguard/app/__init__.py +1 -1
  2. pulp_certguard/app/models.py +7 -26
  3. pulp_certguard/app/serializers.py +0 -2
  4. pulp_certguard/rhsm/__init__.py +4 -0
  5. pulp_certguard/rhsm/rhsm_check_path.py +198 -0
  6. pulp_certguard/tests/unit/certdata.py +249 -0
  7. pulp_certguard/tests/unit/test_rhsm_check_path.py +213 -0
  8. pulp_file/app/__init__.py +1 -1
  9. pulp_file/app/migrations/0001_initial_squashed_0016_add_domain.py +0 -20
  10. pulp_file/app/migrations/0017_alter_filealternatecontentsource_alternatecontentsource_ptr_and_more.py +1 -1
  11. pulpcore/app/apps.py +2 -12
  12. pulpcore/app/entrypoint.py +22 -22
  13. pulpcore/app/migrations/0001_squashed_0090_char_to_text_field.py +0 -95
  14. pulpcore/app/migrations/0091_systemid.py +1 -1
  15. pulp_file/app/migrations/0006_delete_filefilesystemexporter.py → pulpcore/app/migrations/0136_delete_basedistribution.py +3 -3
  16. pulpcore/app/migrations/0137_appstatus.py +33 -0
  17. pulpcore/app/migrations/0138_vulnerabilityreport.py +33 -0
  18. pulpcore/app/models/__init__.py +4 -1
  19. pulpcore/app/models/publication.py +0 -41
  20. pulpcore/app/models/status.py +145 -0
  21. pulpcore/app/models/task.py +1 -0
  22. pulpcore/app/models/vulnerability_report.py +34 -0
  23. pulpcore/app/serializers/__init__.py +1 -0
  24. pulpcore/app/serializers/content.py +13 -1
  25. pulpcore/app/serializers/repository.py +8 -1
  26. pulpcore/app/serializers/vulnerability_report.py +27 -0
  27. pulpcore/app/settings.py +14 -47
  28. pulpcore/app/tasks/__init__.py +2 -0
  29. pulpcore/app/tasks/vulnerability_report.py +159 -0
  30. pulpcore/app/viewsets/__init__.py +1 -0
  31. pulpcore/app/viewsets/vulnerability_report.py +20 -0
  32. pulpcore/constants.py +4 -0
  33. pulpcore/content/__init__.py +23 -22
  34. pulpcore/content/handler.py +5 -2
  35. pulpcore/migrations.py +37 -11
  36. pulpcore/openapi/__init__.py +8 -0
  37. pulpcore/plugin/models/__init__.py +2 -0
  38. pulpcore/plugin/serializers/__init__.py +2 -0
  39. pulpcore/plugin/tasking.py +2 -0
  40. pulpcore/plugin/viewsets/__init__.py +2 -0
  41. pulpcore/pytest_plugin.py +21 -21
  42. pulpcore/tasking/worker.py +38 -35
  43. pulpcore/tests/functional/api/test_auth.py +18 -3
  44. pulpcore/tests/functional/api/test_openapi_schema.py +32 -15
  45. pulpcore/tests/functional/api/using_plugin/test_checkpoint.py +23 -1
  46. pulpcore/tests/functional/api/using_plugin/test_proxy.py +1 -1
  47. pulpcore/tests/unit/content/test_heartbeat.py +11 -8
  48. pulpcore/tests/unit/test_vulnerability_report.py +74 -0
  49. {pulpcore-3.84.0.dist-info → pulpcore-3.85.1.dist-info}/METADATA +12 -17
  50. {pulpcore-3.84.0.dist-info → pulpcore-3.85.1.dist-info}/RECORD +54 -152
  51. pulp_certguard/app/utils.py +0 -28
  52. pulp_certguard/tests/unit/test_models.py +0 -9
  53. pulp_file/app/migrations/0001_initial.py +0 -59
  54. pulp_file/app/migrations/0002_file_related_names.py +0 -55
  55. pulp_file/app/migrations/0003_auto_20191014_1721.py +0 -18
  56. pulp_file/app/migrations/0004_filefilesystemexporter.py +0 -21
  57. pulp_file/app/migrations/0005_filerepository.py +0 -24
  58. pulp_file/app/migrations/0007_filefilesystemexporter.py +0 -25
  59. pulp_file/app/migrations/0008_add_manifest_field.py +0 -19
  60. pulp_file/app/migrations/0009_move_data_to_new_master_distribution_model.py +0 -77
  61. pulp_file/app/migrations/0010_auto_publish.py +0 -23
  62. pulp_file/app/migrations/0011_fix_auto_publish.py +0 -36
  63. pulp_file/app/migrations/0012_delete_filefilesystemexporter.py +0 -28
  64. pulp_file/app/migrations/0013_file_acs.py +0 -24
  65. pulp_file/app/migrations/0014_new_rbac_permissions.py +0 -33
  66. pulp_file/app/migrations/0015_allow_null_manifest.py +0 -23
  67. pulp_file/app/migrations/0016_add_domain.py +0 -25
  68. pulpcore/app/migrations/0001_initial.py +0 -451
  69. pulpcore/app/migrations/0002_increase_artifact_size_field.py +0 -18
  70. pulpcore/app/migrations/0003_remove_upload_completed.py +0 -17
  71. pulpcore/app/migrations/0004_add_duplicated_reserved_resources.py +0 -45
  72. pulpcore/app/migrations/0005_progressreport_code.py +0 -19
  73. pulpcore/app/migrations/0006_repository_plugin_managed.py +0 -18
  74. pulpcore/app/migrations/0007_delete_progress_proxies.py +0 -19
  75. pulpcore/app/migrations/0008_published_metadata_as_content.py +0 -44
  76. pulpcore/app/migrations/0009_remove_task_non_fatal_errors.py +0 -17
  77. pulpcore/app/migrations/0010_pulp_fields.py +0 -570
  78. pulpcore/app/migrations/0011_relative_path.py +0 -28
  79. pulpcore/app/migrations/0012_auto_20191104_2000.py +0 -31
  80. pulpcore/app/migrations/0013_repository_pulp_type.py +0 -18
  81. pulpcore/app/migrations/0014_remove_repository_plugin_managed.py +0 -17
  82. pulpcore/app/migrations/0015_auto_20191112_1426.py +0 -33
  83. pulpcore/app/migrations/0016_charfield_to_textfield.py +0 -68
  84. pulpcore/app/migrations/0017_remove_task_parent.py +0 -17
  85. pulpcore/app/migrations/0018_auto_20191127_2350.py +0 -20
  86. pulpcore/app/migrations/0019_add_signing_service_model.py +0 -27
  87. pulpcore/app/migrations/0020_change_publishedartifact_constraints.py +0 -17
  88. pulpcore/app/migrations/0021_add_signing_service_foreign_key.py +0 -24
  89. pulpcore/app/migrations/0022_rename_last_version.py +0 -27
  90. pulpcore/app/migrations/0023_change_exporter_models.py +0 -82
  91. pulpcore/app/migrations/0024_use_local_storage_for_uploads.py +0 -19
  92. pulpcore/app/migrations/0025_task_parent_task.py +0 -19
  93. pulpcore/app/migrations/0026_task_group.py +0 -32
  94. pulpcore/app/migrations/0027_export_backend.py +0 -31
  95. pulpcore/app/migrations/0028_import_importer_pulpimporter_pulpimporterrepository.py +0 -85
  96. pulpcore/app/migrations/0029_export_delete.py +0 -19
  97. pulpcore/app/migrations/0030_taskgroup_all_tasks_dispatched.py +0 -24
  98. pulpcore/app/migrations/0031_import_export_validate_params.py +0 -19
  99. pulpcore/app/migrations/0032_export_to_chunks.py +0 -27
  100. pulpcore/app/migrations/0033_increase_remote_artifact_size_field.py +0 -18
  101. pulpcore/app/migrations/0034_groupprogressreport.py +0 -32
  102. pulpcore/app/migrations/0035_content_upstream_id.py +0 -18
  103. pulpcore/app/migrations/0036_unprotect_last_export.py +0 -19
  104. pulpcore/app/migrations/0037_pulptemporaryfile.py +0 -28
  105. pulpcore/app/migrations/0038_repository_remote.py +0 -19
  106. pulpcore/app/migrations/0039_change_download_concurrency.py +0 -25
  107. pulpcore/app/migrations/0040_set_admin_is_staff.py +0 -28
  108. pulpcore/app/migrations/0041_accesspolicy.py +0 -29
  109. pulpcore/app/migrations/0042_rbac_for_tasks.py +0 -56
  110. pulpcore/app/migrations/0043_toc_attribute.py +0 -19
  111. pulpcore/app/migrations/0044_temp_file_artifact_field.py +0 -20
  112. pulpcore/app/migrations/0045_accesspolicy_permissions_allow_null.py +0 -19
  113. pulpcore/app/migrations/0046_task__resource_job_id.py +0 -35
  114. pulpcore/app/migrations/0047_improve_orphan_cleanup.py +0 -59
  115. pulpcore/app/migrations/0048_fips_checksums.py +0 -38
  116. pulpcore/app/migrations/0049_add_file_field_to_uploadchunk.py +0 -24
  117. pulpcore/app/migrations/0050_namespace_access_policies.py +0 -28
  118. pulpcore/app/migrations/0051_timeoutfields.py +0 -34
  119. pulpcore/app/migrations/0052_tasking_logging_cid.py +0 -18
  120. pulpcore/app/migrations/0053_remote_headers.py +0 -19
  121. pulpcore/app/migrations/0054_add_public_key.py +0 -104
  122. pulpcore/app/migrations/0055_label.py +0 -31
  123. pulpcore/app/migrations/0056_remote_rate_limit.py +0 -18
  124. pulpcore/app/migrations/0057_add_label_indexes.py +0 -23
  125. pulpcore/app/migrations/0058_accesspolicy_customized.py +0 -18
  126. pulpcore/app/migrations/0059_proxy_creds.py +0 -23
  127. pulpcore/app/migrations/0060_data_migration_proxy_creds.py +0 -45
  128. pulpcore/app/migrations/0061_call_handle_artifact_checksums_command.py +0 -87
  129. pulpcore/app/migrations/0062_add_new_distribution_mastermodel.py +0 -36
  130. pulpcore/app/migrations/0063_repository_retained_versions.py +0 -18
  131. pulpcore/app/migrations/0064_add_new_style_task_columns.py +0 -109
  132. pulpcore/app/migrations/0064_repository_user_hidden.py +0 -18
  133. pulpcore/app/migrations/0065_merge_20210615_1211.py +0 -14
  134. pulpcore/app/migrations/0066_download_concurrency_and_retry_changes.py +0 -24
  135. pulpcore/app/migrations/0067_add_protect_to_task_reservation.py +0 -19
  136. pulpcore/app/migrations/0068_add_timestamp_of_interest.py +0 -23
  137. pulpcore/app/migrations/0069_update_json_fields.py +0 -63
  138. pulpcore/app/migrations/0070_rename_retained_versions.py +0 -18
  139. pulpcore/app/migrations/0071_filesystemexport_filesystemexporter.py +0 -35
  140. pulpcore/app/migrations/0072_add_method_to_filesystem_exporter.py +0 -18
  141. pulpcore/app/migrations/0073_encrypt_remote_fields.py +0 -139
  142. pulpcore/app/migrations/0074_acs.py +0 -47
  143. pulpcore/app/migrations/0075_rbaccontentguard.py +0 -25
  144. pulpcore/app/migrations/0076_remove_reserved_resource.py +0 -39
  145. pulpcore/app/migrations/0077_move_remote_url_credentials.py +0 -41
  146. pulpcore/app/migrations/0078_grouprole_role_userrole.py +0 -70
  147. pulpcore/app/migrations/0079_rename_permissions_assignment_accesspolicy_creation_hooks.py +0 -18
  148. pulpcore/app/migrations/0080_proxy_group_model.py +0 -37
  149. pulpcore/app/migrations/0081_reapplabel_group_permissions.py +0 -59
  150. pulpcore/app/migrations/0082_add_manage_roles_permissions.py +0 -17
  151. pulpcore/app/migrations/0083_alter_group_options.py +0 -17
  152. pulpcore/app/migrations/0084_alter_rbaccontentguard_options.py +0 -17
  153. pulpcore/app/migrations/0085_contentredirectcontentguard.py +0 -26
  154. pulpcore/app/migrations/0086_task_json_fields.py +0 -77
  155. pulpcore/app/migrations/0087_taskschedule.py +0 -34
  156. pulpcore/app/migrations/0088_accesspolicy_queryset_scoping.py +0 -18
  157. pulpcore/app/migrations/0089_alter_contentredirectcontentguard_options.py +0 -17
  158. pulpcore/app/migrations/0090_char_to_text_field.py +0 -79
  159. pulpcore/tests/unit/migration/test_0077_move_remote_url_credentials.py +0 -35
  160. {pulpcore-3.84.0.dist-info → pulpcore-3.85.1.dist-info}/WHEEL +0 -0
  161. {pulpcore-3.84.0.dist-info → pulpcore-3.85.1.dist-info}/entry_points.txt +0 -0
  162. {pulpcore-3.84.0.dist-info → pulpcore-3.85.1.dist-info}/licenses/LICENSE +0 -0
  163. {pulpcore-3.84.0.dist-info → pulpcore-3.85.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,213 @@
1
+ from cryptography import x509
2
+ import pytest
3
+
4
+ from . import certdata
5
+
6
+ from pulp_certguard.rhsm import check_path
7
+ from pulp_certguard.rhsm.rhsm_check_path import (
8
+ bitstream,
9
+ Entitlement,
10
+ HuffmannNode,
11
+ cert_version,
12
+ split_count,
13
+ V1_PATH_OID_REGEX,
14
+ )
15
+
16
+
17
+ @pytest.fixture(scope="session")
18
+ def ent_v1() -> x509.Certificate:
19
+ return x509.load_pem_x509_certificate(certdata.ENTITLEMENT_CERT_V1_0.encode())
20
+
21
+
22
+ @pytest.fixture(scope="session")
23
+ def ent_v3_0() -> x509.Certificate:
24
+ return x509.load_pem_x509_certificate(certdata.ENTITLEMENT_CERT_V3_0.encode())
25
+
26
+
27
+ @pytest.fixture(scope="session")
28
+ def ent_v3_2() -> x509.Certificate:
29
+ return x509.load_pem_x509_certificate(certdata.ENTITLEMENT_CERT_V3_2.encode())
30
+
31
+
32
+ @pytest.fixture(scope="session", params=["3.0", "3.2"])
33
+ def ent_v3_version(request: pytest.FixtureRequest) -> str:
34
+ return request.param
35
+
36
+
37
+ @pytest.fixture(scope="session")
38
+ def ent_v3(ent_v3_version: str) -> x509.Certificate:
39
+ ver = ent_v3_version.replace(".", "_")
40
+ attribute = f"ENTITLEMENT_CERT_V{ver}"
41
+ return x509.load_pem_x509_certificate(getattr(certdata, attribute).encode())
42
+
43
+
44
+ class TestSplitCount:
45
+ """
46
+ If the first byte is < 128, that is the count itself.
47
+ Otherwise the 7 lsb describe the number of bytes to combine to the count.
48
+ """
49
+
50
+ @pytest.mark.parametrize(
51
+ "header, count",
52
+ [
53
+ pytest.param(b"\x00", 0, id="short zero"),
54
+ pytest.param(b"\x0a", 10, id="short ten"),
55
+ pytest.param(b"\x7f", 127, id="short max"),
56
+ pytest.param(b"\x80", 0, id="zero bytes zero"),
57
+ pytest.param(b"\x81\x00", 0, id="one byte zero"),
58
+ pytest.param(b"\x81\x01", 1, id="one byte one"),
59
+ pytest.param(b"\x81\xff", 255, id="one byte max"),
60
+ pytest.param(b"\x84\x00\x00\x00\x00", 0, id="four bytes zero"),
61
+ pytest.param(b"\x84\x00\x00\x00\x01", 1, id="four bytes one"),
62
+ pytest.param(b"\x84\x00\x00\x01\x00", 256, id="four bytes 256"),
63
+ pytest.param(b"\x84\x00\x00\x01\x04", 260, id="four bytes 260"),
64
+ ],
65
+ )
66
+ def test_returns_count_from(self, header: bytes, count: int) -> None:
67
+ assert split_count(header + b"\xde\xad\xbe\xaf") == (count, b"\xde\xad\xbe\xaf")
68
+
69
+
70
+ class TestBitstream:
71
+ def test_0000_produces_16_false(self) -> None:
72
+ assert list(bitstream(b"\x00\x00")) == [False] * 16
73
+
74
+ def test_0001_produces_15_false_true(self) -> None:
75
+ assert list(bitstream(b"\x00\x01")) == [False] * 15 + [True]
76
+
77
+ def test_fff0_produces_12_true_4_false(self) -> None:
78
+ assert list(bitstream(b"\xff\xf0")) == [True] * 12 + [False] * 4
79
+
80
+
81
+ def test_product_certificate_has_subject() -> None:
82
+ cert = x509.load_pem_x509_certificate(certdata.PRODUCT_CERT_V1_0.encode())
83
+ assert cert.subject.rfc4514_string() == "CN=100000000000002"
84
+
85
+
86
+ class TestV1EntitlementCertificate:
87
+ def test_has_subject(self, ent_v1: x509.Certificate) -> None:
88
+ assert ent_v1.subject.rfc4514_string() == "CN=ff80808138574bd20138574d85a50b2f"
89
+
90
+ def test_has_4_paths(self, ent_v1: x509.Certificate) -> None:
91
+ assert (
92
+ len(
93
+ [ext for ext in ent_v1.extensions if V1_PATH_OID_REGEX.match(ext.oid.dotted_string)]
94
+ )
95
+ == 4
96
+ )
97
+
98
+ def test_has_version_1_0(self, ent_v1: x509.Certificate) -> None:
99
+ assert cert_version(ent_v1) == "1.0"
100
+
101
+
102
+ class TestV3EntitlementCertificate:
103
+ def test_cert_version(self, ent_v3_version: str, ent_v3: x509.Certificate) -> None:
104
+ assert cert_version(ent_v3) == ent_v3_version
105
+
106
+
107
+ class TestEntitlement:
108
+ @pytest.fixture(scope="class")
109
+ def entitlement(self, ent_v3: x509.Certificate) -> Entitlement:
110
+ return Entitlement(ent_v3)
111
+
112
+ @pytest.fixture(scope="class")
113
+ def word_tree(self, ent_v3: x509.Certificate) -> "HuffmannNode[str]":
114
+ lex_data, _, _ = Entitlement._split_payload(Entitlement._read_payload(ent_v3))
115
+ return Entitlement._build_word_tree(lex_data)
116
+
117
+ def test_has_node_count_10(self, ent_v3: x509.Certificate) -> None:
118
+ _, node_count, _ = Entitlement._split_payload(Entitlement._read_payload(ent_v3))
119
+ assert node_count == 10
120
+
121
+ def test_00_decodes_to_empty(self, word_tree: "HuffmannNode[str]") -> None:
122
+ assert word_tree.decode(iter([False, False])) == ""
123
+
124
+ def test_100_decodes_to_path(self, word_tree: "HuffmannNode[str]") -> None:
125
+ assert word_tree.decode(iter([True, False, False])) == "path"
126
+
127
+ def test_path_tree_root_contains_foo_and_path(self, entitlement: Entitlement) -> None:
128
+ assert {"foo", "path"} == entitlement._path_tree.keys()
129
+
130
+ def test_path_tree_contains_foo_path_never(self, entitlement: Entitlement) -> None:
131
+ assert entitlement._path_tree["foo"]["path"]["never"] == {}
132
+
133
+ def test_path_tree_contains_foo_path_var_always(self, entitlement: Entitlement) -> None:
134
+ assert entitlement._path_tree["foo"]["path"]["always"]["$releasever"] == {}
135
+
136
+
137
+ class TestCheckPathV1:
138
+ @pytest.mark.parametrize(
139
+ "path",
140
+ (
141
+ "/foo/path/never",
142
+ "/foo/path/never/",
143
+ "//foo/path/never/",
144
+ "/foo/path/never/bar/a/b/c",
145
+ "/foo/path/never/bar//a/b/c",
146
+ "/foo//path/never/bar//a/b/c",
147
+ ),
148
+ )
149
+ def test_matches_foo_path_never(self, ent_v1: x509.Certificate, path: str) -> None:
150
+ assert check_path(ent_v1, path)
151
+
152
+ @pytest.mark.parametrize(
153
+ "path",
154
+ (
155
+ pytest.param("/path/never", id="misses the first part"),
156
+ pytest.param("foo", id="is only the middle part"),
157
+ "/foo",
158
+ "/foo/",
159
+ pytest.param("/foo/path/", id="misses the last part"),
160
+ pytest.param("baz/foo/path/never", id="prepended parts"),
161
+ pytest.param("/path/to//bar/awesomeos", id="substituted an empty string"),
162
+ pytest.param("/path/to/foo/bar/awesomeo", id="misses the last character"),
163
+ pytest.param("/path/to/foo/bar/awesomeos1", id="adds characters at the end"),
164
+ ),
165
+ )
166
+ def test_rejects_a_path_that(self, ent_v1: x509.Certificate, path: str) -> None:
167
+ assert not check_path(ent_v1, path)
168
+
169
+ @pytest.mark.parametrize(
170
+ "path",
171
+ (
172
+ "/path/to/foo/bar/awesomeos",
173
+ "/path/to/foo/bar/awesomeos/",
174
+ "/path/to/foo/bar/awesomeos/a/b/c",
175
+ "/path/to//bar/foo/awesomeos",
176
+ ),
177
+ )
178
+ def test_matches_path_with_substituted_variables(
179
+ self, ent_v1: x509.Certificate, path: str
180
+ ) -> None:
181
+ assert check_path(ent_v1, path)
182
+
183
+
184
+ class TestCheckPathV3:
185
+ @pytest.mark.parametrize(
186
+ "path",
187
+ (
188
+ pytest.param("/foo/path/never", id="exact path without vars"),
189
+ pytest.param("/foo/path/never/a/b/c", id="exact path with extra segments"),
190
+ pytest.param(
191
+ "////foo///path//never///", id="exact path without vars and extra slashes"
192
+ ),
193
+ pytest.param("foo/path/always/c-3po", id="exact path with variable"),
194
+ pytest.param("/path/to/awesomeos/x86_64", id="another exact path without vars"),
195
+ pytest.param("/path/to/c-3po/r2-d2/awesomeos", id="another exact path with vars"),
196
+ ),
197
+ )
198
+ def test_matches(self, ent_v3: x509.Certificate, path: str) -> None:
199
+ assert check_path(ent_v3, path)
200
+
201
+ @pytest.mark.parametrize(
202
+ "path",
203
+ (
204
+ pytest.param("/a/path/to/wherever", id="lunatic path"),
205
+ pytest.param("", id="empty path"),
206
+ pytest.param("////", id="just slashes"),
207
+ pytest.param("foo", id="to short path"),
208
+ pytest.param("path/never", id="path with front segment missing"),
209
+ pytest.param("content/foo/path/never", id="path with extra front segment"),
210
+ ),
211
+ )
212
+ def test_rejects(self, ent_v3: x509.Certificate, path: str) -> None:
213
+ assert not check_path(ent_v3, path)
pulp_file/app/__init__.py CHANGED
@@ -8,6 +8,6 @@ class PulpFilePluginAppConfig(PulpPluginAppConfig):
8
8
 
9
9
  name = "pulp_file.app"
10
10
  label = "file"
11
- version = "3.84.0"
11
+ version = "3.85.1"
12
12
  python_package_name = "pulpcore"
13
13
  domain_compatible = True
@@ -7,28 +7,8 @@ import pulpcore.app.util
7
7
 
8
8
  class Migration(migrations.Migration):
9
9
 
10
- replaces = [
11
- ("file", "0001_initial"),
12
- ("file", "0002_file_related_names"),
13
- ("file", "0003_auto_20191014_1721"),
14
- ("file", "0004_filefilesystemexporter"),
15
- ("file", "0005_filerepository"),
16
- ("file", "0006_delete_filefilesystemexporter"),
17
- ("file", "0007_filefilesystemexporter"),
18
- ("file", "0008_add_manifest_field"),
19
- ("file", "0009_move_data_to_new_master_distribution_model"),
20
- ("file", "0010_auto_publish"),
21
- ("file", "0011_fix_auto_publish"),
22
- ("file", "0012_delete_filefilesystemexporter"),
23
- ("file", "0013_file_acs"),
24
- ("file", "0014_new_rbac_permissions"),
25
- ("file", "0015_allow_null_manifest"),
26
- ("file", "0016_add_domain"),
27
- ]
28
-
29
10
  dependencies = [
30
11
  ("core", "0102_add_domain_relations"),
31
- ("core", "0091_systemid"),
32
12
  ]
33
13
 
34
14
  operations = [
@@ -8,7 +8,7 @@ import pulpcore.app.util
8
8
  class Migration(migrations.Migration):
9
9
 
10
10
  dependencies = [
11
- ('file', '0016_add_domain'),
11
+ ('file', '0001_initial_squashed_0016_add_domain'),
12
12
  ]
13
13
 
14
14
  operations = [
pulpcore/app/apps.py CHANGED
@@ -5,6 +5,7 @@ from gettext import gettext as _
5
5
  from importlib import import_module
6
6
 
7
7
  from django import apps
8
+ from django.conf import settings
8
9
  from django.core.exceptions import ImproperlyConfigured
9
10
  from django.db import connection, transaction
10
11
  from django.db.models.signals import post_migrate
@@ -67,15 +68,6 @@ class PulpPluginAppConfig(apps.AppConfig):
67
68
 
68
69
  def __init__(self, app_name, app_module):
69
70
  super().__init__(app_name, app_module)
70
- # begin Compatilibity layer for DEFAULT_FILE_STORAGE deprecation
71
- # Remove on pulpcore=3.85 or pulpcore=4.0
72
- # * Workaround for getting the up-to-date settings instance, otherwise is doesnt
73
- # get the patch in settings.py
74
- # * Update code in signal handlers to use module-level imports again
75
- from django.conf import settings
76
-
77
- self.settings = settings
78
- # end
79
71
 
80
72
  try:
81
73
  self.version
@@ -247,7 +239,7 @@ class PulpAppConfig(PulpPluginAppConfig):
247
239
  label = "core"
248
240
 
249
241
  # The version of this app
250
- version = "3.84.0"
242
+ version = "3.85.1"
251
243
 
252
244
  # The python package name providing this app
253
245
  python_package_name = "pulpcore"
@@ -322,7 +314,6 @@ def _populate_system_id(sender, apps, verbosity, **kwargs):
322
314
 
323
315
 
324
316
  def _ensure_default_domain(sender, **kwargs):
325
- settings = sender.settings
326
317
  table_names = connection.introspection.table_names()
327
318
  if "core_domain" in table_names:
328
319
  from pulpcore.app.util import get_default_domain
@@ -402,7 +393,6 @@ def adjust_roles(apps, role_prefix, desired_roles, verbosity=1):
402
393
 
403
394
 
404
395
  def _populate_artifact_serving_distribution(sender, apps, verbosity, **kwargs):
405
- settings = sender.settings
406
396
  if (
407
397
  settings.STORAGES["default"]["BACKEND"] == "pulpcore.app.models.storage.FileSystem"
408
398
  or not settings.REDIRECT_TO_OBJECT_STORAGE
@@ -7,7 +7,8 @@ import click
7
7
  import django
8
8
  from django.conf import settings
9
9
  from django.db import connection
10
- from django.db.utils import InterfaceError, DatabaseError
10
+ from django.db.utils import IntegrityError, InterfaceError, DatabaseError
11
+ from gunicorn.arbiter import Arbiter
11
12
  from gunicorn.workers.sync import SyncWorker
12
13
 
13
14
  from pulpcore.app.apps import pulp_plugin_configs
@@ -27,26 +28,21 @@ class PulpApiWorker(SyncWorker):
27
28
 
28
29
  def heartbeat(self):
29
30
  try:
30
- self.api_app_status, created = self.ApiAppStatus.objects.get_or_create(
31
- name=self.name, defaults={"versions": self.versions}
32
- )
33
-
34
- if not created:
35
- self.api_app_status.save_heartbeat()
36
-
37
- if self.api_app_status.versions != self.versions:
38
- self.api_app_status.versions = self.versions
39
- self.api_app_status.save(update_fields=["versions"])
40
-
31
+ self.app_status.save_heartbeat()
41
32
  logger.debug(self.beat_msg)
42
33
  except (InterfaceError, DatabaseError):
43
34
  connection.close_if_unusable_or_obsolete()
44
- logger.info(self.fail_beat_msg)
35
+ try:
36
+ self.app_status.save_heartbeat()
37
+ logger.debug(self.beat_msg)
38
+ except (InterfaceError, DatabaseError):
39
+ logger.error(self.fail_beat_msg)
40
+ exit(Arbiter.WORKER_BOOT_ERROR)
45
41
 
46
42
  def init_process(self):
47
43
  os.environ.setdefault("DJANGO_SETTINGS_MODULE", "pulpcore.app.settings")
48
44
  django.setup()
49
- from pulpcore.app.models import ApiAppStatus
45
+ from pulpcore.app.models import AppStatus
50
46
 
51
47
  if settings.API_APP_TTL < 2 * self.timeout:
52
48
  logger.warning(
@@ -56,9 +52,6 @@ class PulpApiWorker(SyncWorker):
56
52
  self.timeout,
57
53
  )
58
54
 
59
- self.ApiAppStatus = ApiAppStatus
60
- self.api_app_status = None
61
-
62
55
  self.name = "{pid}@{hostname}".format(pid=self.pid, hostname=socket.gethostname())
63
56
  self.versions = {app.label: app.version for app in pulp_plugin_configs()}
64
57
  self.beat_msg = (
@@ -67,9 +60,16 @@ class PulpApiWorker(SyncWorker):
67
60
  )
68
61
  )
69
62
  self.fail_beat_msg = (
70
- "Api App '{name}' failed to write a heartbeat to the database, sleeping for "
71
- "'{interarrival}' seconds."
72
- ).format(name=self.name, interarrival=self.timeout)
63
+ "Api App '{name}' failed to write a heartbeat to the database."
64
+ ).format(name=self.name)
65
+ try:
66
+ self.app_status = AppStatus.objects.create(
67
+ name=self.name, app_type="api", versions=self.versions
68
+ )
69
+ except IntegrityError:
70
+ logger.error(f"An API app with name {self.name} already exists in the database.")
71
+ exit(Arbiter.WORKER_BOOT_ERROR)
72
+
73
73
  super().init_process()
74
74
 
75
75
  def run(self):
@@ -77,8 +77,8 @@ class PulpApiWorker(SyncWorker):
77
77
  super().run()
78
78
  finally:
79
79
  # cleanup
80
- if self.api_app_status:
81
- self.api_app_status.delete()
80
+ if self.app_status:
81
+ self.app_status.delete()
82
82
 
83
83
 
84
84
  class PulpcoreApiApplication(PulpcoreGunicornApplication):
@@ -20,105 +20,10 @@ import uuid
20
20
 
21
21
  class Migration(migrations.Migration):
22
22
 
23
- replaces = [
24
- ("core", "0001_initial"),
25
- ("core", "0002_increase_artifact_size_field"),
26
- ("core", "0003_remove_upload_completed"),
27
- ("core", "0004_add_duplicated_reserved_resources"),
28
- ("core", "0005_progressreport_code"),
29
- ("core", "0006_repository_plugin_managed"),
30
- ("core", "0007_delete_progress_proxies"),
31
- ("core", "0008_published_metadata_as_content"),
32
- ("core", "0009_remove_task_non_fatal_errors"),
33
- ("core", "0010_pulp_fields"),
34
- ("core", "0011_relative_path"),
35
- ("core", "0012_auto_20191104_2000"),
36
- ("core", "0013_repository_pulp_type"),
37
- ("core", "0014_remove_repository_plugin_managed"),
38
- ("core", "0015_auto_20191112_1426"),
39
- ("core", "0016_charfield_to_textfield"),
40
- ("core", "0017_remove_task_parent"),
41
- ("core", "0018_auto_20191127_2350"),
42
- ("core", "0019_add_signing_service_model"),
43
- ("core", "0020_change_publishedartifact_constraints"),
44
- ("core", "0021_add_signing_service_foreign_key"),
45
- ("core", "0022_rename_last_version"),
46
- ("core", "0023_change_exporter_models"),
47
- ("core", "0024_use_local_storage_for_uploads"),
48
- ("core", "0025_task_parent_task"),
49
- ("core", "0026_task_group"),
50
- ("core", "0027_export_backend"),
51
- ("core", "0028_import_importer_pulpimporter_pulpimporterrepository"),
52
- ("core", "0029_export_delete"),
53
- ("core", "0030_taskgroup_all_tasks_dispatched"),
54
- ("core", "0031_import_export_validate_params"),
55
- ("core", "0032_export_to_chunks"),
56
- ("core", "0033_increase_remote_artifact_size_field"),
57
- ("core", "0034_groupprogressreport"),
58
- ("core", "0035_content_upstream_id"),
59
- ("core", "0036_unprotect_last_export"),
60
- ("core", "0037_pulptemporaryfile"),
61
- ("core", "0038_repository_remote"),
62
- ("core", "0039_change_download_concurrency"),
63
- ("core", "0040_set_admin_is_staff"),
64
- ("core", "0041_accesspolicy"),
65
- ("core", "0042_rbac_for_tasks"),
66
- ("core", "0043_toc_attribute"),
67
- ("core", "0044_temp_file_artifact_field"),
68
- ("core", "0045_accesspolicy_permissions_allow_null"),
69
- ("core", "0046_task__resource_job_id"),
70
- ("core", "0047_improve_orphan_cleanup"),
71
- ("core", "0048_fips_checksums"),
72
- ("core", "0049_add_file_field_to_uploadchunk"),
73
- ("core", "0050_namespace_access_policies"),
74
- ("core", "0051_timeoutfields"),
75
- ("core", "0052_tasking_logging_cid"),
76
- ("core", "0053_remote_headers"),
77
- ("core", "0054_add_public_key"),
78
- ("core", "0055_label"),
79
- ("core", "0056_remote_rate_limit"),
80
- ("core", "0057_add_label_indexes"),
81
- ("core", "0058_accesspolicy_customized"),
82
- ("core", "0059_proxy_creds"),
83
- ("core", "0060_data_migration_proxy_creds"),
84
- ("core", "0061_call_handle_artifact_checksums_command"),
85
- ("core", "0062_add_new_distribution_mastermodel"),
86
- ("core", "0063_repository_retained_versions"),
87
- ("core", "0064_repository_user_hidden"),
88
- ("core", "0064_add_new_style_task_columns"),
89
- ("core", "0065_merge_20210615_1211"),
90
- ("core", "0066_download_concurrency_and_retry_changes"),
91
- ("core", "0067_add_protect_to_task_reservation"),
92
- ("core", "0068_add_timestamp_of_interest"),
93
- ("core", "0069_update_json_fields"),
94
- ("core", "0070_rename_retained_versions"),
95
- ("core", "0071_filesystemexport_filesystemexporter"),
96
- ("core", "0072_add_method_to_filesystem_exporter"),
97
- ("core", "0073_encrypt_remote_fields"),
98
- ("core", "0074_acs"),
99
- ("core", "0075_rbaccontentguard"),
100
- ("core", "0076_remove_reserved_resource"),
101
- ("core", "0077_move_remote_url_credentials"),
102
- ("core", "0078_grouprole_role_userrole"),
103
- ("core", "0079_rename_permissions_assignment_accesspolicy_creation_hooks"),
104
- ("core", "0080_proxy_group_model"),
105
- ("core", "0081_reapplabel_group_permissions"),
106
- ("core", "0082_add_manage_roles_permissions"),
107
- ("core", "0083_alter_group_options"),
108
- ("core", "0084_alter_rbaccontentguard_options"),
109
- ("core", "0085_contentredirectcontentguard"),
110
- ("core", "0086_task_json_fields"),
111
- ("core", "0087_taskschedule"),
112
- ("core", "0088_accesspolicy_queryset_scoping"),
113
- ("core", "0089_alter_contentredirectcontentguard_options"),
114
- ("core", "0090_char_to_text_field"),
115
- ]
116
-
117
23
  initial = True
118
24
 
119
25
  dependencies = [
120
26
  ("auth", "0012_alter_user_first_name_max_length"),
121
- ("auth", "__first__"),
122
27
  ("contenttypes", "0002_remove_content_type_name"),
123
28
  ]
124
29
 
@@ -8,7 +8,7 @@ import uuid
8
8
  class Migration(migrations.Migration):
9
9
 
10
10
  dependencies = [
11
- ('core', '0090_char_to_text_field'),
11
+ ('core', '0001_squashed_0090_char_to_text_field'),
12
12
  ]
13
13
 
14
14
  operations = [
@@ -1,4 +1,4 @@
1
- # Generated by Django 2.2.6 on 2020-03-13 16:18
1
+ # Generated by Django 4.2.16 on 2024-12-05 12:37
2
2
 
3
3
  from django.db import migrations
4
4
 
@@ -6,11 +6,11 @@ from django.db import migrations
6
6
  class Migration(migrations.Migration):
7
7
 
8
8
  dependencies = [
9
- ('file', '0005_filerepository'),
9
+ ("core", "0135_task_pulp_task_resources_index"),
10
10
  ]
11
11
 
12
12
  operations = [
13
13
  migrations.DeleteModel(
14
- name='FileFileSystemExporter',
14
+ name="BaseDistribution",
15
15
  ),
16
16
  ]
@@ -0,0 +1,33 @@
1
+ # Generated by Django 4.2.23 on 2025-08-07 08:46
2
+
3
+ import django.contrib.postgres.fields.hstore
4
+ from django.db import migrations, models
5
+ import django_lifecycle.mixins
6
+ import pulpcore.app.models.base
7
+
8
+
9
+ class Migration(migrations.Migration):
10
+
11
+ dependencies = [
12
+ ('core', '0136_delete_basedistribution'),
13
+ ]
14
+
15
+ operations = [
16
+ migrations.CreateModel(
17
+ name='AppStatus',
18
+ fields=[
19
+ ('pulp_id', models.UUIDField(default=pulpcore.app.models.base.pulp_uuid, editable=False, primary_key=True, serialize=False)),
20
+ ('pulp_created', models.DateTimeField(auto_now_add=True)),
21
+ ('pulp_last_updated', models.DateTimeField(auto_now=True, null=True)),
22
+ ('app_type', models.CharField(choices=[('api', 'api'), ('content', 'content'), ('worker', 'worker')], max_length=10)),
23
+ ('name', models.TextField(db_index=True, unique=True)),
24
+ ('versions', django.contrib.postgres.fields.hstore.HStoreField(default=dict)),
25
+ ('ttl', models.DurationField()),
26
+ ('last_heartbeat', models.DateTimeField(auto_now=True)),
27
+ ],
28
+ options={
29
+ 'abstract': False,
30
+ },
31
+ bases=(django_lifecycle.mixins.LifecycleModelMixin, models.Model),
32
+ ),
33
+ ]
@@ -0,0 +1,33 @@
1
+ # Generated by Django 4.2.19 on 2025-08-07 00:07
2
+
3
+ from django.db import migrations, models
4
+ import django.db.models.deletion
5
+ import django_lifecycle.mixins
6
+ import pulpcore.app.models.base
7
+ import pulpcore.app.util
8
+
9
+
10
+ class Migration(migrations.Migration):
11
+
12
+ dependencies = [
13
+ ('core', '0137_appstatus'),
14
+ ]
15
+
16
+ operations = [
17
+ migrations.CreateModel(
18
+ name='VulnerabilityReport',
19
+ fields=[
20
+ ('pulp_id', models.UUIDField(default=pulpcore.app.models.base.pulp_uuid, editable=False, primary_key=True, serialize=False)),
21
+ ('pulp_created', models.DateTimeField(auto_now_add=True)),
22
+ ('pulp_last_updated', models.DateTimeField(auto_now=True, null=True)),
23
+ ('vulns', models.JSONField()),
24
+ ('content', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='core.content')),
25
+ ('pulp_domain', models.ForeignKey(default=pulpcore.app.util.get_domain_pk, on_delete=django.db.models.deletion.CASCADE, to='core.domain')),
26
+ ('repo_versions', models.ManyToManyField(blank=True, to='core.repositoryversion')),
27
+ ],
28
+ options={
29
+ 'default_related_name': '%(app_label)s_%(model_name)s',
30
+ },
31
+ bases=(django_lifecycle.mixins.LifecycleModelMixin, models.Model),
32
+ ),
33
+ ]
@@ -69,7 +69,7 @@ from .repository import (
69
69
  RepositoryVersionContentDetails,
70
70
  )
71
71
 
72
- from .status import ApiAppStatus, ContentAppStatus
72
+ from .status import AppStatus, ApiAppStatus, ContentAppStatus
73
73
 
74
74
  from .task import (
75
75
  CreatedResource,
@@ -87,6 +87,8 @@ from .upload import (
87
87
  UploadChunk,
88
88
  )
89
89
 
90
+ from .vulnerability_report import VulnerabilityReport
91
+
90
92
  # Moved here to avoid a circular import with Task
91
93
  from .progress import GroupProgressReport, ProgressReport
92
94
 
@@ -170,4 +172,5 @@ __all__ = [
170
172
  "OpenPGPSignature",
171
173
  "OpenPGPUserAttribute",
172
174
  "OpenPGPUserID",
175
+ "VulnerabilityReport",
173
176
  ]
@@ -576,47 +576,6 @@ class CompositeContentGuard(ContentGuard, AutoAddObjPermsMixin):
576
576
  )
577
577
 
578
578
 
579
- class BaseDistribution(MasterModel):
580
- """
581
- A distribution defines how a publication is distributed by the Content App.
582
-
583
- This abstract model can be used by plugin writers to create concrete distributions that are
584
- stored in separate tables from the Distributions provided by pulpcore.
585
-
586
- The `name` must be unique.
587
-
588
- The ``base_path`` must have no overlapping components. So if a Distribution with ``base_path``
589
- of ``a/path/foo`` existed, you could not make a second Distribution with a ``base_path`` of
590
- ``a/path`` or ``a`` because both are subpaths of ``a/path/foo``.
591
-
592
- Note:
593
- This class is no longer supported and cannot be removed from Pulp 3 due to possible
594
- problems with old migrations for plugins. Until the migrations are squashed, this class
595
- should be preserved.
596
-
597
- Fields:
598
- name (models.TextField): The name of the distribution. Examples: "rawhide" and "stable".
599
- base_path (models.TextField): The base (relative) path component of the published url.
600
-
601
- Relations:
602
- content_guard (models.ForeignKey): An optional content-guard.
603
- remote (models.ForeignKey): A remote that the content app can use to find content not
604
- yet stored in Pulp.
605
- """
606
-
607
- name = models.TextField(db_index=True, unique=True)
608
- base_path = models.TextField(unique=True)
609
-
610
- content_guard = models.ForeignKey(ContentGuard, null=True, on_delete=models.SET_NULL)
611
- remote = models.ForeignKey(Remote, null=True, on_delete=models.SET_NULL)
612
-
613
- def __init__(self, *args, **kwargs):
614
- raise Exception(
615
- "BaseDistribution is no longer supported. "
616
- "Please use pulpcore.plugin.models.Distribution instead."
617
- )
618
-
619
-
620
579
  class Distribution(MasterModel):
621
580
  """
622
581
  A Distribution defines how the Content App distributes a publication or repository_version.