patchman 4.0.11__tar.gz → 4.0.13__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 (353) hide show
  1. {patchman-4.0.11 → patchman-4.0.13}/PKG-INFO +1 -1
  2. patchman-4.0.13/VERSION.txt +1 -0
  3. {patchman-4.0.11 → patchman-4.0.13}/errata/models.py +0 -1
  4. {patchman-4.0.11 → patchman-4.0.13}/errata/tests/test_models.py +19 -0
  5. {patchman-4.0.11 → patchman-4.0.13}/hosts/models.py +287 -36
  6. patchman-4.0.13/hosts/tests/test_models.py +699 -0
  7. {patchman-4.0.11 → patchman-4.0.13}/hosts/utils.py +7 -3
  8. {patchman-4.0.11 → patchman-4.0.13}/patchman.egg-info/PKG-INFO +1 -1
  9. {patchman-4.0.11 → patchman-4.0.13}/patchman.egg-info/SOURCES.txt +1 -1
  10. patchman-4.0.11/VERSION.txt +0 -1
  11. patchman-4.0.11/hosts/tests/test_models.py +0 -130
  12. {patchman-4.0.11 → patchman-4.0.13}/AUTHORS +0 -0
  13. {patchman-4.0.11 → patchman-4.0.13}/COPYING +0 -0
  14. {patchman-4.0.11 → patchman-4.0.13}/INSTALL.md +0 -0
  15. {patchman-4.0.11 → patchman-4.0.13}/MANIFEST.in +0 -0
  16. {patchman-4.0.11 → patchman-4.0.13}/README.md +0 -0
  17. {patchman-4.0.11 → patchman-4.0.13}/arch/__init__.py +0 -0
  18. {patchman-4.0.11 → patchman-4.0.13}/arch/admin.py +0 -0
  19. {patchman-4.0.11 → patchman-4.0.13}/arch/apps.py +0 -0
  20. {patchman-4.0.11 → patchman-4.0.13}/arch/migrations/0001_initial.py +0 -0
  21. {patchman-4.0.11 → patchman-4.0.13}/arch/migrations/0002_alter_machinearchitecture_options_and_more.py +0 -0
  22. {patchman-4.0.11 → patchman-4.0.13}/arch/migrations/__init__.py +0 -0
  23. {patchman-4.0.11 → patchman-4.0.13}/arch/models.py +0 -0
  24. {patchman-4.0.11 → patchman-4.0.13}/arch/serializers.py +0 -0
  25. {patchman-4.0.11 → patchman-4.0.13}/arch/tests/__init__.py +0 -0
  26. {patchman-4.0.11 → patchman-4.0.13}/arch/tests/test_api.py +0 -0
  27. {patchman-4.0.11 → patchman-4.0.13}/arch/tests/test_models.py +0 -0
  28. {patchman-4.0.11 → patchman-4.0.13}/arch/utils.py +0 -0
  29. {patchman-4.0.11 → patchman-4.0.13}/arch/views.py +0 -0
  30. {patchman-4.0.11 → patchman-4.0.13}/domains/__init__.py +0 -0
  31. {patchman-4.0.11 → patchman-4.0.13}/domains/admin.py +0 -0
  32. {patchman-4.0.11 → patchman-4.0.13}/domains/apps.py +0 -0
  33. {patchman-4.0.11 → patchman-4.0.13}/domains/migrations/0001_initial.py +0 -0
  34. {patchman-4.0.11 → patchman-4.0.13}/domains/migrations/0002_alter_domain_options.py +0 -0
  35. {patchman-4.0.11 → patchman-4.0.13}/domains/migrations/__init__.py +0 -0
  36. {patchman-4.0.11 → patchman-4.0.13}/domains/models.py +0 -0
  37. {patchman-4.0.11 → patchman-4.0.13}/domains/serializers.py +0 -0
  38. {patchman-4.0.11 → patchman-4.0.13}/domains/tests/__init__.py +0 -0
  39. {patchman-4.0.11 → patchman-4.0.13}/domains/tests/test_api.py +0 -0
  40. {patchman-4.0.11 → patchman-4.0.13}/domains/tests/test_models.py +0 -0
  41. {patchman-4.0.11 → patchman-4.0.13}/domains/views.py +0 -0
  42. {patchman-4.0.11 → patchman-4.0.13}/errata/__init__.py +0 -0
  43. {patchman-4.0.11 → patchman-4.0.13}/errata/admin.py +0 -0
  44. {patchman-4.0.11 → patchman-4.0.13}/errata/apps.py +0 -0
  45. {patchman-4.0.11 → patchman-4.0.13}/errata/managers.py +0 -0
  46. {patchman-4.0.11 → patchman-4.0.13}/errata/migrations/0001_initial.py +0 -0
  47. {patchman-4.0.11 → patchman-4.0.13}/errata/migrations/0002_alter_erratumreference_unique_together.py +0 -0
  48. {patchman-4.0.11 → patchman-4.0.13}/errata/migrations/0003_delete_erratumreference_alter_erratum_references.py +0 -0
  49. {patchman-4.0.11 → patchman-4.0.13}/errata/migrations/0004_rename_packages_erratum_fixed_packages.py +0 -0
  50. {patchman-4.0.11 → patchman-4.0.13}/errata/migrations/0005_erratum_affected_packages_and_more.py +0 -0
  51. {patchman-4.0.11 → patchman-4.0.13}/errata/migrations/0006_alter_erratum_options.py +0 -0
  52. {patchman-4.0.11 → patchman-4.0.13}/errata/migrations/0007_alter_erratum_fixed_packages.py +0 -0
  53. {patchman-4.0.11 → patchman-4.0.13}/errata/migrations/0008_add_cached_count_fields.py +0 -0
  54. {patchman-4.0.11 → patchman-4.0.13}/errata/migrations/0009_backfill_cached_counts.py +0 -0
  55. {patchman-4.0.11 → patchman-4.0.13}/errata/migrations/__init__.py +0 -0
  56. {patchman-4.0.11 → patchman-4.0.13}/errata/serializers.py +0 -0
  57. {patchman-4.0.11 → patchman-4.0.13}/errata/signals.py +0 -0
  58. {patchman-4.0.11 → patchman-4.0.13}/errata/sources/__init__.py +0 -0
  59. {patchman-4.0.11 → patchman-4.0.13}/errata/sources/distros/__init__.py +0 -0
  60. {patchman-4.0.11 → patchman-4.0.13}/errata/sources/distros/alma.py +0 -0
  61. {patchman-4.0.11 → patchman-4.0.13}/errata/sources/distros/arch.py +0 -0
  62. {patchman-4.0.11 → patchman-4.0.13}/errata/sources/distros/centos.py +0 -0
  63. {patchman-4.0.11 → patchman-4.0.13}/errata/sources/distros/debian.py +0 -0
  64. {patchman-4.0.11 → patchman-4.0.13}/errata/sources/distros/rocky.py +0 -0
  65. {patchman-4.0.11 → patchman-4.0.13}/errata/sources/distros/ubuntu.py +0 -0
  66. {patchman-4.0.11 → patchman-4.0.13}/errata/sources/repos/__init__.py +0 -0
  67. {patchman-4.0.11 → patchman-4.0.13}/errata/sources/repos/yum.py +0 -0
  68. {patchman-4.0.11 → patchman-4.0.13}/errata/tables.py +0 -0
  69. {patchman-4.0.11 → patchman-4.0.13}/errata/tasks.py +0 -0
  70. {patchman-4.0.11 → patchman-4.0.13}/errata/templates/errata/erratum_detail.html +0 -0
  71. {patchman-4.0.11 → patchman-4.0.13}/errata/templates/errata/erratum_list.html +0 -0
  72. {patchman-4.0.11 → patchman-4.0.13}/errata/tests/__init__.py +0 -0
  73. {patchman-4.0.11 → patchman-4.0.13}/errata/tests/test_api.py +0 -0
  74. {patchman-4.0.11 → patchman-4.0.13}/errata/tests/test_integration.py +0 -0
  75. {patchman-4.0.11 → patchman-4.0.13}/errata/urls.py +0 -0
  76. {patchman-4.0.11 → patchman-4.0.13}/errata/utils.py +0 -0
  77. {patchman-4.0.11 → patchman-4.0.13}/errata/views.py +0 -0
  78. {patchman-4.0.11 → patchman-4.0.13}/etc/patchman/apache.conf.example +0 -0
  79. {patchman-4.0.11 → patchman-4.0.13}/etc/patchman/celery.conf +0 -0
  80. {patchman-4.0.11 → patchman-4.0.13}/etc/patchman/local_settings.py +0 -0
  81. {patchman-4.0.11 → patchman-4.0.13}/etc/systemd/system/patchman-celery-beat.service +0 -0
  82. /patchman-4.0.11/etc/systemd/system/patchman-celery-worker.service → /patchman-4.0.13/etc/systemd/system/patchman-celery-worker@.service +0 -0
  83. {patchman-4.0.11 → patchman-4.0.13}/hosts/__init__.py +0 -0
  84. {patchman-4.0.11 → patchman-4.0.13}/hosts/admin.py +0 -0
  85. {patchman-4.0.11 → patchman-4.0.13}/hosts/apps.py +0 -0
  86. {patchman-4.0.11 → patchman-4.0.13}/hosts/forms.py +0 -0
  87. {patchman-4.0.11 → patchman-4.0.13}/hosts/managers.py +0 -0
  88. {patchman-4.0.11 → patchman-4.0.13}/hosts/migrations/0001_initial.py +0 -0
  89. {patchman-4.0.11 → patchman-4.0.13}/hosts/migrations/0002_initial.py +0 -0
  90. {patchman-4.0.11 → patchman-4.0.13}/hosts/migrations/0003_host_modules.py +0 -0
  91. {patchman-4.0.11 → patchman-4.0.13}/hosts/migrations/0004_remove_host_tags_host_tags.py +0 -0
  92. {patchman-4.0.11 → patchman-4.0.13}/hosts/migrations/0005_rename_os_host_osvariant.py +0 -0
  93. {patchman-4.0.11 → patchman-4.0.13}/hosts/migrations/0006_migrate_to_tz_aware.py +0 -0
  94. {patchman-4.0.11 → patchman-4.0.13}/hosts/migrations/0007_alter_host_tags.py +0 -0
  95. {patchman-4.0.11 → patchman-4.0.13}/hosts/migrations/0008_alter_host_options.py +0 -0
  96. {patchman-4.0.11 → patchman-4.0.13}/hosts/migrations/0009_host_errata.py +0 -0
  97. {patchman-4.0.11 → patchman-4.0.13}/hosts/migrations/0010_alter_hostrepo_options.py +0 -0
  98. {patchman-4.0.11 → patchman-4.0.13}/hosts/migrations/0011_host_bug_updates_count_host_errata_count_and_more.py +0 -0
  99. {patchman-4.0.11 → patchman-4.0.13}/hosts/migrations/0012_backfill_cached_counts.py +0 -0
  100. {patchman-4.0.11 → patchman-4.0.13}/hosts/migrations/__init__.py +0 -0
  101. {patchman-4.0.11 → patchman-4.0.13}/hosts/serializers.py +0 -0
  102. {patchman-4.0.11 → patchman-4.0.13}/hosts/signals.py +0 -0
  103. {patchman-4.0.11 → patchman-4.0.13}/hosts/tables.py +0 -0
  104. {patchman-4.0.11 → patchman-4.0.13}/hosts/tasks.py +0 -0
  105. {patchman-4.0.11 → patchman-4.0.13}/hosts/templates/hosts/host_delete.html +0 -0
  106. {patchman-4.0.11 → patchman-4.0.13}/hosts/templates/hosts/host_detail.html +0 -0
  107. {patchman-4.0.11 → patchman-4.0.13}/hosts/templates/hosts/host_edit.html +0 -0
  108. {patchman-4.0.11 → patchman-4.0.13}/hosts/templates/hosts/host_list.html +0 -0
  109. {patchman-4.0.11 → patchman-4.0.13}/hosts/templatetags/__init__.py +0 -0
  110. {patchman-4.0.11 → patchman-4.0.13}/hosts/templatetags/report_alert.py +0 -0
  111. {patchman-4.0.11 → patchman-4.0.13}/hosts/tests/__init__.py +0 -0
  112. {patchman-4.0.11 → patchman-4.0.13}/hosts/tests/test_api.py +0 -0
  113. {patchman-4.0.11 → patchman-4.0.13}/hosts/tests/test_find_updates.py +0 -0
  114. {patchman-4.0.11 → patchman-4.0.13}/hosts/tests/test_managers.py +0 -0
  115. {patchman-4.0.11 → patchman-4.0.13}/hosts/urls.py +0 -0
  116. {patchman-4.0.11 → patchman-4.0.13}/hosts/views.py +0 -0
  117. {patchman-4.0.11 → patchman-4.0.13}/modules/__init__.py +0 -0
  118. {patchman-4.0.11 → patchman-4.0.13}/modules/admin.py +0 -0
  119. {patchman-4.0.11 → patchman-4.0.13}/modules/apps.py +0 -0
  120. {patchman-4.0.11 → patchman-4.0.13}/modules/managers.py +0 -0
  121. {patchman-4.0.11 → patchman-4.0.13}/modules/migrations/0001_initial.py +0 -0
  122. {patchman-4.0.11 → patchman-4.0.13}/modules/migrations/0002_auto_20240204_2214.py +0 -0
  123. {patchman-4.0.11 → patchman-4.0.13}/modules/migrations/0003_alter_module_options.py +0 -0
  124. {patchman-4.0.11 → patchman-4.0.13}/modules/migrations/0004_alter_module_options.py +0 -0
  125. {patchman-4.0.11 → patchman-4.0.13}/modules/migrations/0005_alter_module_unique_together.py +0 -0
  126. {patchman-4.0.11 → patchman-4.0.13}/modules/migrations/__init__.py +0 -0
  127. {patchman-4.0.11 → patchman-4.0.13}/modules/models.py +0 -0
  128. {patchman-4.0.11 → patchman-4.0.13}/modules/serializers.py +0 -0
  129. {patchman-4.0.11 → patchman-4.0.13}/modules/tables.py +0 -0
  130. {patchman-4.0.11 → patchman-4.0.13}/modules/templates/modules/module_detail.html +0 -0
  131. {patchman-4.0.11 → patchman-4.0.13}/modules/templates/modules/module_list.html +0 -0
  132. {patchman-4.0.11 → patchman-4.0.13}/modules/urls.py +0 -0
  133. {patchman-4.0.11 → patchman-4.0.13}/modules/utils.py +0 -0
  134. {patchman-4.0.11 → patchman-4.0.13}/modules/views.py +0 -0
  135. {patchman-4.0.11 → patchman-4.0.13}/operatingsystems/__init__.py +0 -0
  136. {patchman-4.0.11 → patchman-4.0.13}/operatingsystems/admin.py +0 -0
  137. {patchman-4.0.11 → patchman-4.0.13}/operatingsystems/apps.py +0 -0
  138. {patchman-4.0.11 → patchman-4.0.13}/operatingsystems/fixtures/os.json +0 -0
  139. {patchman-4.0.11 → patchman-4.0.13}/operatingsystems/fixtures/osgroup.json +0 -0
  140. {patchman-4.0.11 → patchman-4.0.13}/operatingsystems/forms.py +0 -0
  141. {patchman-4.0.11 → patchman-4.0.13}/operatingsystems/managers.py +0 -0
  142. {patchman-4.0.11 → patchman-4.0.13}/operatingsystems/migrations/0001_initial.py +0 -0
  143. {patchman-4.0.11 → patchman-4.0.13}/operatingsystems/migrations/0002_initial.py +0 -0
  144. {patchman-4.0.11 → patchman-4.0.13}/operatingsystems/migrations/0003_os_arch.py +0 -0
  145. {patchman-4.0.11 → patchman-4.0.13}/operatingsystems/migrations/0003_osgroup_codename.py +0 -0
  146. {patchman-4.0.11 → patchman-4.0.13}/operatingsystems/migrations/0004_alter_osgroup_unique_together.py +0 -0
  147. {patchman-4.0.11 → patchman-4.0.13}/operatingsystems/migrations/0005_rename_osgroup_osrelease_rename_os_osvariant_and_more.py +0 -0
  148. {patchman-4.0.11 → patchman-4.0.13}/operatingsystems/migrations/0006_osrelease_cpe_name_osvariant_codename.py +0 -0
  149. {patchman-4.0.11 → patchman-4.0.13}/operatingsystems/migrations/0007_alter_osrelease_unique_together.py +0 -0
  150. {patchman-4.0.11 → patchman-4.0.13}/operatingsystems/migrations/0008_alter_osrelease_options_alter_osvariant_options.py +0 -0
  151. {patchman-4.0.11 → patchman-4.0.13}/operatingsystems/migrations/0009_osvariant_hosts_count.py +0 -0
  152. {patchman-4.0.11 → patchman-4.0.13}/operatingsystems/migrations/0010_backfill_osvariant_counts.py +0 -0
  153. {patchman-4.0.11 → patchman-4.0.13}/operatingsystems/migrations/__init__.py +0 -0
  154. {patchman-4.0.11 → patchman-4.0.13}/operatingsystems/models.py +0 -0
  155. {patchman-4.0.11 → patchman-4.0.13}/operatingsystems/serializers.py +0 -0
  156. {patchman-4.0.11 → patchman-4.0.13}/operatingsystems/signals.py +0 -0
  157. {patchman-4.0.11 → patchman-4.0.13}/operatingsystems/tables.py +0 -0
  158. {patchman-4.0.11 → patchman-4.0.13}/operatingsystems/templates/operatingsystems/os_landing.html +0 -0
  159. {patchman-4.0.11 → patchman-4.0.13}/operatingsystems/templates/operatingsystems/osrelease_delete.html +0 -0
  160. {patchman-4.0.11 → patchman-4.0.13}/operatingsystems/templates/operatingsystems/osrelease_detail.html +0 -0
  161. {patchman-4.0.11 → patchman-4.0.13}/operatingsystems/templates/operatingsystems/osrelease_list.html +0 -0
  162. {patchman-4.0.11 → patchman-4.0.13}/operatingsystems/templates/operatingsystems/osvariant_delete.html +0 -0
  163. {patchman-4.0.11 → patchman-4.0.13}/operatingsystems/templates/operatingsystems/osvariant_delete_multiple.html +0 -0
  164. {patchman-4.0.11 → patchman-4.0.13}/operatingsystems/templates/operatingsystems/osvariant_detail.html +0 -0
  165. {patchman-4.0.11 → patchman-4.0.13}/operatingsystems/templates/operatingsystems/osvariant_list.html +0 -0
  166. {patchman-4.0.11 → patchman-4.0.13}/operatingsystems/tests/__init__.py +0 -0
  167. {patchman-4.0.11 → patchman-4.0.13}/operatingsystems/tests/test_api.py +0 -0
  168. {patchman-4.0.11 → patchman-4.0.13}/operatingsystems/tests/test_models.py +0 -0
  169. {patchman-4.0.11 → patchman-4.0.13}/operatingsystems/urls.py +0 -0
  170. {patchman-4.0.11 → patchman-4.0.13}/operatingsystems/utils.py +0 -0
  171. {patchman-4.0.11 → patchman-4.0.13}/operatingsystems/views.py +0 -0
  172. {patchman-4.0.11 → patchman-4.0.13}/packages/__init__.py +0 -0
  173. {patchman-4.0.11 → patchman-4.0.13}/packages/admin.py +0 -0
  174. {patchman-4.0.11 → patchman-4.0.13}/packages/apps.py +0 -0
  175. {patchman-4.0.11 → patchman-4.0.13}/packages/managers.py +0 -0
  176. {patchman-4.0.11 → patchman-4.0.13}/packages/migrations/0001_initial.py +0 -0
  177. {patchman-4.0.11 → patchman-4.0.13}/packages/migrations/0002_auto_20250207_1319.py +0 -0
  178. {patchman-4.0.11 → patchman-4.0.13}/packages/migrations/0002_delete_erratum_delete_erratumreference.py +0 -0
  179. {patchman-4.0.11 → patchman-4.0.13}/packages/migrations/0003_auto_20250207_1746.py +0 -0
  180. {patchman-4.0.11 → patchman-4.0.13}/packages/migrations/0004_alter_package_options_alter_packagecategory_options_and_more.py +0 -0
  181. {patchman-4.0.11 → patchman-4.0.13}/packages/migrations/0005_alter_package_packagetype.py +0 -0
  182. {patchman-4.0.11 → patchman-4.0.13}/packages/migrations/0006_alter_packageupdate_options.py +0 -0
  183. {patchman-4.0.11 → patchman-4.0.13}/packages/migrations/__init__.py +0 -0
  184. {patchman-4.0.11 → patchman-4.0.13}/packages/models.py +0 -0
  185. {patchman-4.0.11 → patchman-4.0.13}/packages/serializers.py +0 -0
  186. {patchman-4.0.11 → patchman-4.0.13}/packages/tables.py +0 -0
  187. {patchman-4.0.11 → patchman-4.0.13}/packages/templates/packages/package_detail.html +0 -0
  188. {patchman-4.0.11 → patchman-4.0.13}/packages/templates/packages/package_list.html +0 -0
  189. {patchman-4.0.11 → patchman-4.0.13}/packages/templates/packages/package_name_detail.html +0 -0
  190. {patchman-4.0.11 → patchman-4.0.13}/packages/templates/packages/package_name_list.html +0 -0
  191. {patchman-4.0.11 → patchman-4.0.13}/packages/tests/__init__.py +0 -0
  192. {patchman-4.0.11 → patchman-4.0.13}/packages/tests/test_api.py +0 -0
  193. {patchman-4.0.11 → patchman-4.0.13}/packages/tests/test_models.py +0 -0
  194. {patchman-4.0.11 → patchman-4.0.13}/packages/tests/test_version_compare.py +0 -0
  195. {patchman-4.0.11 → patchman-4.0.13}/packages/urls.py +0 -0
  196. {patchman-4.0.11 → patchman-4.0.13}/packages/utils.py +0 -0
  197. {patchman-4.0.11 → patchman-4.0.13}/packages/views.py +0 -0
  198. {patchman-4.0.11 → patchman-4.0.13}/patchman/__init__.py +0 -0
  199. {patchman-4.0.11 → patchman-4.0.13}/patchman/celery.py +0 -0
  200. {patchman-4.0.11 → patchman-4.0.13}/patchman/receivers.py +0 -0
  201. {patchman-4.0.11 → patchman-4.0.13}/patchman/settings.py +0 -0
  202. {patchman-4.0.11 → patchman-4.0.13}/patchman/signals.py +0 -0
  203. {patchman-4.0.11 → patchman-4.0.13}/patchman/sqlite3/base.py +0 -0
  204. {patchman-4.0.11 → patchman-4.0.13}/patchman/static/css/base.css +0 -0
  205. {patchman-4.0.11 → patchman-4.0.13}/patchman/static/js/expandable-text.js +0 -0
  206. {patchman-4.0.11 → patchman-4.0.13}/patchman/static/js/sidebar.js +0 -0
  207. {patchman-4.0.11 → patchman-4.0.13}/patchman/urls.py +0 -0
  208. {patchman-4.0.11 → patchman-4.0.13}/patchman/wsgi.py +0 -0
  209. {patchman-4.0.11 → patchman-4.0.13}/patchman.egg-info/dependency_links.txt +0 -0
  210. {patchman-4.0.11 → patchman-4.0.13}/patchman.egg-info/requires.txt +0 -0
  211. {patchman-4.0.11 → patchman-4.0.13}/patchman.egg-info/top_level.txt +0 -0
  212. {patchman-4.0.11 → patchman-4.0.13}/reports/__init__.py +0 -0
  213. {patchman-4.0.11 → patchman-4.0.13}/reports/admin.py +0 -0
  214. {patchman-4.0.11 → patchman-4.0.13}/reports/apps.py +0 -0
  215. {patchman-4.0.11 → patchman-4.0.13}/reports/migrations/0001_initial.py +0 -0
  216. {patchman-4.0.11 → patchman-4.0.13}/reports/migrations/0002_report_modules.py +0 -0
  217. {patchman-4.0.11 → patchman-4.0.13}/reports/migrations/0003_remove_report_accessed.py +0 -0
  218. {patchman-4.0.11 → patchman-4.0.13}/reports/migrations/0004_migrate_to_tz_aware.py +0 -0
  219. {patchman-4.0.11 → patchman-4.0.13}/reports/migrations/0005_alter_report_options.py +0 -0
  220. {patchman-4.0.11 → patchman-4.0.13}/reports/migrations/__init__.py +0 -0
  221. {patchman-4.0.11 → patchman-4.0.13}/reports/models.py +0 -0
  222. {patchman-4.0.11 → patchman-4.0.13}/reports/serializers.py +0 -0
  223. {patchman-4.0.11 → patchman-4.0.13}/reports/tables.py +0 -0
  224. {patchman-4.0.11 → patchman-4.0.13}/reports/tasks.py +0 -0
  225. {patchman-4.0.11 → patchman-4.0.13}/reports/templates/reports/report.txt +0 -0
  226. {patchman-4.0.11 → patchman-4.0.13}/reports/templates/reports/report_delete.html +0 -0
  227. {patchman-4.0.11 → patchman-4.0.13}/reports/templates/reports/report_detail.html +0 -0
  228. {patchman-4.0.11 → patchman-4.0.13}/reports/templates/reports/report_list.html +0 -0
  229. {patchman-4.0.11 → patchman-4.0.13}/reports/tests/__init__.py +0 -0
  230. {patchman-4.0.11 → patchman-4.0.13}/reports/tests/test_api.py +0 -0
  231. {patchman-4.0.11 → patchman-4.0.13}/reports/tests/test_edge_cases.py +0 -0
  232. {patchman-4.0.11 → patchman-4.0.13}/reports/tests/test_integration.py +0 -0
  233. {patchman-4.0.11 → patchman-4.0.13}/reports/tests/test_models.py +0 -0
  234. {patchman-4.0.11 → patchman-4.0.13}/reports/tests/test_parsing.py +0 -0
  235. {patchman-4.0.11 → patchman-4.0.13}/reports/tests/test_serializers.py +0 -0
  236. {patchman-4.0.11 → patchman-4.0.13}/reports/tests/test_tasks.py +0 -0
  237. {patchman-4.0.11 → patchman-4.0.13}/reports/tests/test_utils.py +0 -0
  238. {patchman-4.0.11 → patchman-4.0.13}/reports/urls.py +0 -0
  239. {patchman-4.0.11 → patchman-4.0.13}/reports/utils.py +0 -0
  240. {patchman-4.0.11 → patchman-4.0.13}/reports/views.py +0 -0
  241. {patchman-4.0.11 → patchman-4.0.13}/repos/__init__.py +0 -0
  242. {patchman-4.0.11 → patchman-4.0.13}/repos/admin.py +0 -0
  243. {patchman-4.0.11 → patchman-4.0.13}/repos/apps.py +0 -0
  244. {patchman-4.0.11 → patchman-4.0.13}/repos/forms.py +0 -0
  245. {patchman-4.0.11 → patchman-4.0.13}/repos/managers.py +0 -0
  246. {patchman-4.0.11 → patchman-4.0.13}/repos/migrations/0001_initial.py +0 -0
  247. {patchman-4.0.11 → patchman-4.0.13}/repos/migrations/0002_alter_repository_repotype.py +0 -0
  248. {patchman-4.0.11 → patchman-4.0.13}/repos/migrations/0003_migrate_to_tz_aware.py +0 -0
  249. {patchman-4.0.11 → patchman-4.0.13}/repos/migrations/0004_rename_file_checksum_mirror_package_checksum.py +0 -0
  250. {patchman-4.0.11 → patchman-4.0.13}/repos/migrations/0005_rename_package_checksum_mirror_packages_checksum.py +0 -0
  251. {patchman-4.0.11 → patchman-4.0.13}/repos/migrations/0006_mirror_errata_checksum_mirror_modules_checksum.py +0 -0
  252. {patchman-4.0.11 → patchman-4.0.13}/repos/migrations/0007_alter_mirror_options_alter_mirrorpackage_options_and_more.py +0 -0
  253. {patchman-4.0.11 → patchman-4.0.13}/repos/migrations/0008_mirror_packages_count.py +0 -0
  254. {patchman-4.0.11 → patchman-4.0.13}/repos/migrations/0009_backfill_mirror_counts.py +0 -0
  255. {patchman-4.0.11 → patchman-4.0.13}/repos/migrations/__init__.py +0 -0
  256. {patchman-4.0.11 → patchman-4.0.13}/repos/models.py +0 -0
  257. {patchman-4.0.11 → patchman-4.0.13}/repos/repo_types/__init__.py +0 -0
  258. {patchman-4.0.11 → patchman-4.0.13}/repos/repo_types/arch.py +0 -0
  259. {patchman-4.0.11 → patchman-4.0.13}/repos/repo_types/deb.py +0 -0
  260. {patchman-4.0.11 → patchman-4.0.13}/repos/repo_types/gentoo.py +0 -0
  261. {patchman-4.0.11 → patchman-4.0.13}/repos/repo_types/rpm.py +0 -0
  262. {patchman-4.0.11 → patchman-4.0.13}/repos/repo_types/yast.py +0 -0
  263. {patchman-4.0.11 → patchman-4.0.13}/repos/repo_types/yum.py +0 -0
  264. {patchman-4.0.11 → patchman-4.0.13}/repos/serializers.py +0 -0
  265. {patchman-4.0.11 → patchman-4.0.13}/repos/signals.py +0 -0
  266. {patchman-4.0.11 → patchman-4.0.13}/repos/tables.py +0 -0
  267. {patchman-4.0.11 → patchman-4.0.13}/repos/tasks.py +0 -0
  268. {patchman-4.0.11 → patchman-4.0.13}/repos/templates/repos/mirror_delete.html +0 -0
  269. {patchman-4.0.11 → patchman-4.0.13}/repos/templates/repos/mirror_detail.html +0 -0
  270. {patchman-4.0.11 → patchman-4.0.13}/repos/templates/repos/mirror_edit.html +0 -0
  271. {patchman-4.0.11 → patchman-4.0.13}/repos/templates/repos/mirror_list.html +0 -0
  272. {patchman-4.0.11 → patchman-4.0.13}/repos/templates/repos/mirror_with_repo_list.html +0 -0
  273. {patchman-4.0.11 → patchman-4.0.13}/repos/templates/repos/repo_delete.html +0 -0
  274. {patchman-4.0.11 → patchman-4.0.13}/repos/templates/repos/repo_detail.html +0 -0
  275. {patchman-4.0.11 → patchman-4.0.13}/repos/templates/repos/repo_edit.html +0 -0
  276. {patchman-4.0.11 → patchman-4.0.13}/repos/templates/repos/repo_list.html +0 -0
  277. {patchman-4.0.11 → patchman-4.0.13}/repos/templatetags/__init__.py +0 -0
  278. {patchman-4.0.11 → patchman-4.0.13}/repos/tests/__init__.py +0 -0
  279. {patchman-4.0.11 → patchman-4.0.13}/repos/tests/test_api.py +0 -0
  280. {patchman-4.0.11 → patchman-4.0.13}/repos/tests/test_managers.py +0 -0
  281. {patchman-4.0.11 → patchman-4.0.13}/repos/tests/test_mirror_sync.py +0 -0
  282. {patchman-4.0.11 → patchman-4.0.13}/repos/tests/test_models.py +0 -0
  283. {patchman-4.0.11 → patchman-4.0.13}/repos/urls.py +0 -0
  284. {patchman-4.0.11 → patchman-4.0.13}/repos/utils.py +0 -0
  285. {patchman-4.0.11 → patchman-4.0.13}/repos/views.py +0 -0
  286. {patchman-4.0.11 → patchman-4.0.13}/requirements.txt +0 -0
  287. {patchman-4.0.11 → patchman-4.0.13}/sbin/patchman +0 -0
  288. {patchman-4.0.11 → patchman-4.0.13}/sbin/patchman-manage +0 -0
  289. {patchman-4.0.11 → patchman-4.0.13}/sbin/patchman-set-secret-key +0 -0
  290. {patchman-4.0.11 → patchman-4.0.13}/scripts/clear-django-logs.py +0 -0
  291. {patchman-4.0.11 → patchman-4.0.13}/scripts/create_graph.sh +0 -0
  292. {patchman-4.0.11 → patchman-4.0.13}/scripts/rpm-install.sh +0 -0
  293. {patchman-4.0.11 → patchman-4.0.13}/scripts/rpm-post-install.sh +0 -0
  294. {patchman-4.0.11 → patchman-4.0.13}/security/__init__.py +0 -0
  295. {patchman-4.0.11 → patchman-4.0.13}/security/admin.py +0 -0
  296. {patchman-4.0.11 → patchman-4.0.13}/security/apps.py +0 -0
  297. {patchman-4.0.11 → patchman-4.0.13}/security/managers.py +0 -0
  298. {patchman-4.0.11 → patchman-4.0.13}/security/migrations/0001_initial.py +0 -0
  299. {patchman-4.0.11 → patchman-4.0.13}/security/migrations/0002_alter_cve_options.py +0 -0
  300. {patchman-4.0.11 → patchman-4.0.13}/security/migrations/0003_alter_cve_description_alter_cwe_description.py +0 -0
  301. {patchman-4.0.11 → patchman-4.0.13}/security/migrations/0004_alter_cve_options.py +0 -0
  302. {patchman-4.0.11 → patchman-4.0.13}/security/migrations/0005_reference_cve_references.py +0 -0
  303. {patchman-4.0.11 → patchman-4.0.13}/security/migrations/0006_alter_cve_options_alter_cvss_unique_together.py +0 -0
  304. {patchman-4.0.11 → patchman-4.0.13}/security/migrations/0007_remove_cve_title.py +0 -0
  305. {patchman-4.0.11 → patchman-4.0.13}/security/migrations/0008_alter_cwe_options_alter_reference_options.py +0 -0
  306. {patchman-4.0.11 → patchman-4.0.13}/security/migrations/__init__.py +0 -0
  307. {patchman-4.0.11 → patchman-4.0.13}/security/models.py +0 -0
  308. {patchman-4.0.11 → patchman-4.0.13}/security/serializers.py +0 -0
  309. {patchman-4.0.11 → patchman-4.0.13}/security/tables.py +0 -0
  310. {patchman-4.0.11 → patchman-4.0.13}/security/tasks.py +0 -0
  311. {patchman-4.0.11 → patchman-4.0.13}/security/templates/security/cve_detail.html +0 -0
  312. {patchman-4.0.11 → patchman-4.0.13}/security/templates/security/cve_list.html +0 -0
  313. {patchman-4.0.11 → patchman-4.0.13}/security/templates/security/cwe_detail.html +0 -0
  314. {patchman-4.0.11 → patchman-4.0.13}/security/templates/security/cwe_list.html +0 -0
  315. {patchman-4.0.11 → patchman-4.0.13}/security/templates/security/reference_list.html +0 -0
  316. {patchman-4.0.11 → patchman-4.0.13}/security/templates/security/security_landing.html +0 -0
  317. {patchman-4.0.11 → patchman-4.0.13}/security/tests/__init__.py +0 -0
  318. {patchman-4.0.11 → patchman-4.0.13}/security/tests/test_api.py +0 -0
  319. {patchman-4.0.11 → patchman-4.0.13}/security/tests/test_models.py +0 -0
  320. {patchman-4.0.11 → patchman-4.0.13}/security/urls.py +0 -0
  321. {patchman-4.0.11 → patchman-4.0.13}/security/utils.py +0 -0
  322. {patchman-4.0.11 → patchman-4.0.13}/security/views.py +0 -0
  323. {patchman-4.0.11 → patchman-4.0.13}/setup.cfg +0 -0
  324. {patchman-4.0.11 → patchman-4.0.13}/setup.py +0 -0
  325. {patchman-4.0.11 → patchman-4.0.13}/util/__init__.py +0 -0
  326. {patchman-4.0.11 → patchman-4.0.13}/util/apps.py +0 -0
  327. {patchman-4.0.11 → patchman-4.0.13}/util/context_processors.py +0 -0
  328. {patchman-4.0.11 → patchman-4.0.13}/util/filterspecs.py +0 -0
  329. {patchman-4.0.11 → patchman-4.0.13}/util/logging.py +0 -0
  330. {patchman-4.0.11 → patchman-4.0.13}/util/management/__init__.py +0 -0
  331. {patchman-4.0.11 → patchman-4.0.13}/util/management/commands/__init__.py +0 -0
  332. {patchman-4.0.11 → patchman-4.0.13}/util/management/commands/create_api_key.py +0 -0
  333. {patchman-4.0.11 → patchman-4.0.13}/util/management/commands/list_api_keys.py +0 -0
  334. {patchman-4.0.11 → patchman-4.0.13}/util/management/commands/revoke_api_key.py +0 -0
  335. {patchman-4.0.11 → patchman-4.0.13}/util/tables.py +0 -0
  336. {patchman-4.0.11 → patchman-4.0.13}/util/tasks.py +0 -0
  337. {patchman-4.0.11 → patchman-4.0.13}/util/templates/404.html +0 -0
  338. {patchman-4.0.11 → patchman-4.0.13}/util/templates/500.html +0 -0
  339. {patchman-4.0.11 → patchman-4.0.13}/util/templates/base.html +0 -0
  340. {patchman-4.0.11 → patchman-4.0.13}/util/templates/bulk_actions.html +0 -0
  341. {patchman-4.0.11 → patchman-4.0.13}/util/templates/dashboard.html +0 -0
  342. {patchman-4.0.11 → patchman-4.0.13}/util/templates/navbar.html +0 -0
  343. {patchman-4.0.11 → patchman-4.0.13}/util/templates/objectlist.html +0 -0
  344. {patchman-4.0.11 → patchman-4.0.13}/util/templates/registration/login.html +0 -0
  345. {patchman-4.0.11 → patchman-4.0.13}/util/templates/searchbar.html +0 -0
  346. {patchman-4.0.11 → patchman-4.0.13}/util/templates/table.html +0 -0
  347. {patchman-4.0.11 → patchman-4.0.13}/util/templatetags/__init__.py +0 -0
  348. {patchman-4.0.11 → patchman-4.0.13}/util/templatetags/common.py +0 -0
  349. {patchman-4.0.11 → patchman-4.0.13}/util/tests/__init__.py +0 -0
  350. {patchman-4.0.11 → patchman-4.0.13}/util/tests/test_commands.py +0 -0
  351. {patchman-4.0.11 → patchman-4.0.13}/util/tests/test_utils.py +0 -0
  352. {patchman-4.0.11 → patchman-4.0.13}/util/urls.py +0 -0
  353. {patchman-4.0.11 → patchman-4.0.13}/util/views.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: patchman
3
- Version: 4.0.11
3
+ Version: 4.0.13
4
4
  Summary: Django based patch status monitoring tool for linux systems
5
5
  Home-page: http://patchman.openbytes.ie/
6
6
  Author: Marcus Furlong
@@ -0,0 +1 @@
1
+ 4.0.13
@@ -149,7 +149,6 @@ class Erratum(models.Model):
149
149
  def add_fixed_packages(self, packages):
150
150
  for package in packages:
151
151
  self.fixed_packages.add(package)
152
- self.save()
153
152
 
154
153
  def add_affected_packages(self, packages):
155
154
  for package in packages:
@@ -239,3 +239,22 @@ class ErratumCachedCountTests(TestCase):
239
239
  self.erratum.refresh_from_db()
240
240
  self.assertEqual(self.erratum.cves_count, self.erratum.cves.count())
241
241
  self.assertEqual(self.erratum.osreleases_count, self.erratum.osreleases.count())
242
+
243
+ def test_add_fixed_packages_no_stale_save(self):
244
+ """Test that add_fixed_packages does not overwrite cached counts.
245
+
246
+ Regression test: add_fixed_packages previously called self.save()
247
+ after the M2M .add() loop, which overwrote the signal-updated
248
+ fixed_packages_count with the stale in-memory value.
249
+ """
250
+ from arch.models import PackageArchitecture
251
+ from packages.models import Package, PackageName
252
+ pkg_arch = PackageArchitecture.objects.create(name='amd64')
253
+ pkg_name = PackageName.objects.create(name='libssl3')
254
+ pkg = Package.objects.create(
255
+ name=pkg_name, arch=pkg_arch, epoch='',
256
+ version='3.0.1', release='1', packagetype='D'
257
+ )
258
+ self.erratum.add_fixed_packages({pkg})
259
+ self.erratum.refresh_from_db()
260
+ self.assertEqual(self.erratum.fixed_packages_count, 1)
@@ -178,27 +178,28 @@ class Host(models.Model):
178
178
  def find_updates(self):
179
179
 
180
180
  kernels_q = Q(name__name='kernel') | \
181
- Q(name__name='kernel-devel') | \
182
- Q(name__name='kernel-preempt') | \
183
- Q(name__name='kernel-preempt-devel') | \
184
- Q(name__name='kernel-rt') | \
185
- Q(name__name='kernel-rt-devel') | \
186
- Q(name__name='kernel-debug') | \
187
- Q(name__name='kernel-debug-devel') | \
188
- Q(name__name='kernel-default') | \
189
- Q(name__name='kernel-default-devel') | \
190
- Q(name__name='kernel-headers') | \
191
- Q(name__name='kernel-core') | \
192
- Q(name__name='kernel-modules') | \
193
- Q(name__name='virtualbox-kmp-default') | \
194
- Q(name__name='virtualbox-kmp-preempt') | \
195
- Q(name__name='kernel-uek') | \
196
- Q(name__name='kernel-uek-devel') | \
197
- Q(name__name='kernel-uek-debug') | \
198
- Q(name__name='kernel-uek-debug-devel') | \
199
- Q(name__name='kernel-uek-container') | \
200
- Q(name__name='kernel-uek-container-debug') | \
201
- Q(name__name='kernel-uek-doc')
181
+ Q(name__name__startswith='kernel-') | \
182
+ Q(name__name__startswith='virtualbox-kmp-') | \
183
+ Q(name__name__startswith='linux-image-') | \
184
+ Q(name__name__startswith='linux-headers-') | \
185
+ Q(name__name__regex=r'^linux-modules-\d') | \
186
+ Q(name__name__regex=r'^linux-modules-extra-\d') | \
187
+ Q(name__name__startswith='linux-tools-') | \
188
+ Q(name__name__startswith='linux-cloud-tools-') | \
189
+ Q(name__name__startswith='linux-kbuild-') | \
190
+ Q(name__name__startswith='linux-support-') | \
191
+ Q(name__name='linux') | \
192
+ Q(name__name='linux-lts') | \
193
+ Q(name__name='linux-zen') | \
194
+ Q(name__name='linux-hardened') | \
195
+ Q(name__name='linux-rt') | \
196
+ Q(name__name='linux-rt-lts') | \
197
+ Q(name__name='linux-headers') | \
198
+ Q(name__name='linux-lts-headers') | \
199
+ Q(name__name='linux-zen-headers') | \
200
+ Q(name__name='linux-hardened-headers') | \
201
+ Q(name__name='linux-rt-headers') | \
202
+ Q(name__name='linux-rt-lts-headers')
202
203
  repo_packages = self.get_host_repo_packages()
203
204
  host_packages = self.packages.exclude(kernels_q).distinct()
204
205
  kernel_packages = self.packages.filter(kernels_q)
@@ -313,42 +314,292 @@ class Host(models.Model):
313
314
  return update_ids
314
315
 
315
316
  def check_if_reboot_required(self, host_highest):
317
+ """Check if a reboot is required (running kernel < installed highest).
316
318
 
317
- ver, rel = self.kernel.split('-')[:2]
319
+ Uses labelCompare for RPM-style version tuples parsed from uname -r.
320
+ Only valid for RPM kernels — DEB and Arch use compare_version via
321
+ their respective find_*_kernel_updates methods.
322
+ """
323
+ parts = self.kernel.split('-')
324
+ if len(parts) < 2:
325
+ return
326
+ ver, rel = parts[:2]
327
+ # strip arch suffix from uname -r release (e.g. '.x86_64', '.aarch64')
328
+ arch_suffix = '.' + self.arch.name
329
+ if rel.endswith(arch_suffix):
330
+ rel = rel[:-len(arch_suffix)]
331
+ # SUSE uname -r truncates the micro release (e.g. '160000.8' vs
332
+ # RPM release '160000.8.1'), so check for prefix match first
333
+ if host_highest.version == ver and \
334
+ (host_highest.release == rel or
335
+ host_highest.release.startswith(rel + '.')):
336
+ self.reboot_required = False
337
+ return
318
338
  kernel_ver = ('', str(ver), str(rel))
319
339
  host_highest_ver = ('', host_highest.version, host_highest.release)
320
340
  if labelCompare(kernel_ver, host_highest_ver) == -1:
321
341
  self.reboot_required = True
322
342
  else:
323
343
  self.reboot_required = False
324
- self.save()
344
+
345
+ def _get_deb_kernel_flavour(self, pkg_name):
346
+ """Extract the flavour suffix from a DEB kernel package name.
347
+
348
+ e.g. 'linux-image-6.8.0-51-generic' → 'generic'
349
+ 'linux-image-6.8.0-51-lowlatency' → 'lowlatency'
350
+ 'linux-image-6.1.0-28-cloud-amd64' → 'cloud-amd64'
351
+ 'linux-modules-extra-6.8.0-51-generic' → 'generic'
352
+ Returns None if the flavour cannot be determined.
353
+ """
354
+ for prefix in self._deb_kernel_prefixes:
355
+ if pkg_name.startswith(prefix):
356
+ # strip prefix, then split version from flavour
357
+ # e.g. '6.8.0-51-generic' or '6.1.0-28-cloud-amd64'
358
+ remainder = pkg_name[len(prefix):]
359
+ # version parts are numeric/dotted, flavour starts after
360
+ # e.g. '6.8.0-51-generic' → parts=['6.8.0', '51', 'generic']
361
+ parts = remainder.split('-')
362
+ # find first non-numeric part (not starting with digit)
363
+ for i, part in enumerate(parts):
364
+ if part and not part[0].isdigit():
365
+ return '-'.join(parts[i:])
366
+ return None
367
+ return None
368
+
369
+ def _get_running_kernel_flavour(self):
370
+ """Extract the flavour from the running kernel string.
371
+
372
+ e.g. '6.8.0-51-generic' → 'generic'
373
+ '6.8.0-51-lowlatency' → 'lowlatency'
374
+ '6.1.0-28-cloud-amd64' → 'cloud-amd64'
375
+ Returns None for RPM-style kernels (no flavour suffix).
376
+ """
377
+ parts = self.kernel.split('-')
378
+ if len(parts) >= 2:
379
+ # find first non-numeric part after the version
380
+ for i, part in enumerate(parts):
381
+ if i > 0 and part and not part[0].isdigit():
382
+ return '-'.join(parts[i:])
383
+ return None
384
+
385
+ # longest prefixes first to avoid linux-modules- matching linux-modules-extra-
386
+ _deb_kernel_prefixes = [
387
+ 'linux-image-unsigned-',
388
+ 'linux-modules-extra-',
389
+ 'linux-cloud-tools-',
390
+ 'linux-image-uc-',
391
+ 'linux-image-',
392
+ 'linux-headers-',
393
+ 'linux-modules-',
394
+ 'linux-support-',
395
+ 'linux-kbuild-',
396
+ 'linux-tools-',
397
+ ]
325
398
 
326
399
  def find_kernel_updates(self, kernel_packages, repo_packages):
327
400
 
328
401
  update_ids = []
402
+ self.reboot_required = False
403
+
404
+ deb_kernels = kernel_packages.filter(packagetype='D')
405
+ rpm_kernels = kernel_packages.filter(packagetype='R')
406
+ arch_kernels = kernel_packages.filter(packagetype='A')
407
+
408
+ update_ids.extend(self._find_rpm_kernel_updates(rpm_kernels, repo_packages))
409
+ update_ids.extend(self._find_deb_kernel_updates(deb_kernels, repo_packages))
410
+ update_ids.extend(self._find_arch_kernel_updates(arch_kernels, repo_packages))
411
+
412
+ self.save(update_fields=['reboot_required'])
413
+ return update_ids
414
+
415
+ def _find_rpm_kernel_updates(self, kernel_packages, repo_packages):
416
+
417
+ update_ids = []
418
+
419
+ # parse running kernel version for comparison
420
+ parts = self.kernel.split('-')
421
+ if len(parts) < 2:
422
+ return update_ids
423
+ ver, rel = parts[:2]
424
+ # strip arch suffix from uname -r release (e.g. '.x86_64')
425
+ arch_suffix = '.' + self.arch.name
426
+ if rel.endswith(arch_suffix):
427
+ rel = rel[:-len(arch_suffix)]
428
+
429
+ # deduplicate: only process each kernel package name once
430
+ processed_names = set()
431
+
329
432
  for package in kernel_packages:
330
- host_highest = package
331
- repo_highest = package
433
+ if package.name_id in processed_names:
434
+ continue
435
+ processed_names.add(package.name_id)
332
436
 
333
437
  pu_q = Q(name=package.name)
334
- potential_updates = repo_packages.filter(pu_q)
335
- for pu in potential_updates:
336
- if package.compare_version(pu) == -1 \
337
- and repo_highest.compare_version(pu) == -1:
438
+
439
+ # find repo highest for this kernel name
440
+ repo_highest = None
441
+ for pu in repo_packages.filter(pu_q):
442
+ if repo_highest is None or repo_highest.compare_version(pu) == -1:
338
443
  repo_highest = pu
339
444
 
340
- host_packages = self.packages.filter(pu_q)
341
- for hp in host_packages:
342
- if package.compare_version(hp) == -1 and \
343
- host_highest.compare_version(hp) == -1:
445
+ if repo_highest is None:
446
+ continue
447
+
448
+ # find host highest installed for reboot check
449
+ host_highest = None
450
+ running_package = None
451
+ for hp in self.packages.filter(pu_q):
452
+ if host_highest is None or host_highest.compare_version(hp) == -1:
344
453
  host_highest = hp
454
+ # match installed package to running kernel
455
+ # SUSE uname -r truncates micro release ('160000.8' vs
456
+ # RPM '160000.8.1') so use prefix match with dot boundary
457
+ if hp.version == ver and \
458
+ (hp.release == rel or
459
+ hp.release.startswith(rel + '.')):
460
+ running_package = hp
461
+
462
+ # for the running kernel's flavour, compare running vs repo
463
+ # for other flavours, compare highest installed vs repo
464
+ if running_package:
465
+ base_package = running_package
466
+ else:
467
+ base_package = host_highest
345
468
 
346
- if host_highest.compare_version(repo_highest) == -1:
347
- uid = self.process_update(host_highest, repo_highest)
469
+ if base_package and base_package.compare_version(repo_highest) == -1:
470
+ uid = self.process_update(base_package, repo_highest)
348
471
  if uid is not None:
349
472
  update_ids.append(uid)
350
473
 
351
- self.check_if_reboot_required(host_highest)
474
+ # reboot check only on primary kernel packages
475
+ if host_highest and package.name.name in (
476
+ 'kernel', 'kernel-core', 'kernel-debug-core',
477
+ 'kernel-default', 'kernel-rt', 'kernel-azure',
478
+ 'kernel-kvmsmall',
479
+ 'kernel-uek', 'kernel-uki-virt', 'kernel-debug-uki-virt',
480
+ ):
481
+ self.check_if_reboot_required(host_highest)
482
+
483
+ return update_ids
484
+
485
+ def _find_arch_kernel_updates(self, kernel_packages, repo_packages):
486
+
487
+ update_ids = []
488
+
489
+ for package in kernel_packages:
490
+ pu_q = Q(name=package.name)
491
+
492
+ repo_highest = None
493
+ for rp in repo_packages.filter(pu_q):
494
+ if repo_highest is None or repo_highest.compare_version(rp) == -1:
495
+ repo_highest = rp
496
+
497
+ if repo_highest is None:
498
+ continue
499
+
500
+ if package.compare_version(repo_highest) == -1:
501
+ uid = self.process_update(package, repo_highest)
502
+ if uid is not None:
503
+ update_ids.append(uid)
504
+
505
+ # reboot check for main kernel packages (not -headers)
506
+ # Arch uname -r format varies by flavour:
507
+ # linux: 6.12.8-arch1-1 (pkgver=6.12.8.arch1)
508
+ # linux-lts: 6.1.68-1-lts (pkgver=6.1.68)
509
+ # linux-zen: 6.12.8-zen1-1-zen (pkgver=6.12.8.zen1)
510
+ # The only reliable common part is the base version (first segment
511
+ # of uname -r) which maps to the numeric prefix of pkgver
512
+ if package.name.name in (
513
+ 'linux', 'linux-lts', 'linux-zen', 'linux-hardened',
514
+ 'linux-rt', 'linux-rt-lts',
515
+ ):
516
+ running_base = self.kernel.split('-')[0] if self.kernel else ''
517
+ pkg_ver = package.version
518
+ # pkgver is either 'X.Y.Z' (lts) or 'X.Y.Z.flavourN' (others)
519
+ # check if the package version matches or extends the base
520
+ if pkg_ver != running_base and not pkg_ver.startswith(running_base + '.'):
521
+ self.reboot_required = True
522
+
523
+ return update_ids
524
+
525
+ def _find_deb_kernel_updates(self, kernel_packages, repo_packages):
526
+
527
+ update_ids = []
528
+ running_flavour = self._get_running_kernel_flavour()
529
+
530
+ # find the linux-image package matching the running kernel
531
+ running_kernel_pkg = None
532
+ for package in kernel_packages:
533
+ pkg_name = package.name.name
534
+ if pkg_name.startswith('linux-image-') and pkg_name.endswith(self.kernel):
535
+ running_kernel_pkg = package
536
+ break
537
+
538
+ processed_prefixes = set()
539
+ for package in kernel_packages:
540
+ pkg_name = package.name.name
541
+ flavour = self._get_deb_kernel_flavour(pkg_name)
542
+
543
+ # if we know the running flavour, only process matching packages
544
+ # if we don't (unflavoured kernel), process all kernel packages
545
+ if running_flavour and flavour != running_flavour:
546
+ continue
547
+
548
+ # determine the prefix (e.g. 'linux-image-')
549
+ prefix = None
550
+ for p in self._deb_kernel_prefixes:
551
+ if pkg_name.startswith(p):
552
+ prefix = p
553
+ break
554
+ if prefix is None or prefix in processed_prefixes:
555
+ continue
556
+ processed_prefixes.add(prefix)
557
+
558
+ # build endswith filter for flavoured kernels
559
+ name_filter = Q(
560
+ name__name__startswith=prefix,
561
+ packagetype='D',
562
+ )
563
+ if running_flavour:
564
+ name_filter &= Q(name__name__endswith=f'-{running_flavour}')
565
+
566
+ # find repo highest for this prefix+flavour
567
+ repo_highest = None
568
+ for rp in repo_packages.filter(name_filter):
569
+ if repo_highest is None or repo_highest.compare_version(rp) == -1:
570
+ repo_highest = rp
571
+
572
+ if repo_highest is None:
573
+ continue
574
+
575
+ # find the installed package matching the running kernel for this prefix
576
+ base_package = None
577
+ expected_name = prefix + self.kernel
578
+ for hp in self.packages.filter(name_filter):
579
+ if hp.name.name == expected_name:
580
+ base_package = hp
581
+ break
582
+
583
+ # fallback: if no running match, use the installed package we started with
584
+ if base_package is None:
585
+ base_package = package
586
+
587
+ if base_package.compare_version(repo_highest) == -1:
588
+ uid = self.process_update(base_package, repo_highest)
589
+ if uid is not None:
590
+ update_ids.append(uid)
591
+
592
+ # reboot check: see if a newer linux-image is installed but not running
593
+ # use compare_version (DEB semantics) instead of labelCompare
594
+ if running_kernel_pkg:
595
+ for package in kernel_packages:
596
+ if package.name.name.startswith('linux-image-'):
597
+ flavour = self._get_deb_kernel_flavour(package.name.name)
598
+ if running_flavour is None or flavour == running_flavour:
599
+ if running_kernel_pkg.compare_version(package) == -1:
600
+ self.reboot_required = True
601
+ break
602
+
352
603
  return update_ids
353
604
 
354
605