cmdbsyncer 4.3.2__tar.gz → 4.3.4__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 (452) hide show
  1. {cmdbsyncer-4.3.2/cmdbsyncer.egg-info → cmdbsyncer-4.3.4}/PKG-INFO +1 -1
  2. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/__init__.py +7 -0
  3. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/auth/views.py +11 -2
  4. cmdbsyncer-4.3.4/application/buildinfo.txt +1 -0
  5. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/changelog/v4.3.md +11 -0
  6. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/enterprise.py +43 -1
  7. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/models/user.py +10 -1
  8. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/tests/test_cmk_rules.py +4 -4
  9. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/tests/test_inventorize.py +3 -3
  10. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/tests/test_users.py +47 -0
  11. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/users.py +11 -6
  12. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/maintenance/__init__.py +38 -4
  13. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/license_info.html +2 -1
  14. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/views/license.py +8 -12
  15. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4/cmdbsyncer.egg-info}/PKG-INFO +1 -1
  16. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/cmdbsyncer.egg-info/SOURCES.txt +5 -0
  17. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/pyproject.toml +1 -1
  18. cmdbsyncer-4.3.4/tests/test_config_dir.py +112 -0
  19. cmdbsyncer-4.3.4/tests/test_enterprise_quiet.py +145 -0
  20. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_regex_condition_limits.py +1 -1
  21. cmdbsyncer-4.3.4/tests/test_user_scope_smoke.py +232 -0
  22. cmdbsyncer-4.3.4/tests/test_web_boot_smoke.py +54 -0
  23. cmdbsyncer-4.3.4/tests/test_web_requests_smoke.py +122 -0
  24. cmdbsyncer-4.3.2/application/buildinfo.txt +0 -1
  25. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/LICENSE +0 -0
  26. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/README.md +0 -0
  27. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/_version.py +0 -0
  28. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/api/__init__.py +0 -0
  29. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/api/inventory.py +0 -0
  30. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/api/objects.py +0 -0
  31. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/api/rules.py +0 -0
  32. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/api/syncer.py +0 -0
  33. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/api/views.py +0 -0
  34. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/changelog/.pages +0 -0
  35. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/changelog/v3.10.md +0 -0
  36. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/changelog/v3.11.md +0 -0
  37. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/changelog/v3.12.md +0 -0
  38. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/changelog/v3.5.md +0 -0
  39. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/changelog/v3.7.md +0 -0
  40. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/changelog/v3.8.md +0 -0
  41. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/changelog/v3.9.md +0 -0
  42. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/changelog/v4.0.md +0 -0
  43. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/changelog/v4.1.md +0 -0
  44. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/changelog/v4.2.md +0 -0
  45. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/cli.py +0 -0
  46. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/config.py +0 -0
  47. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/docu_links.py +0 -0
  48. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/helpers/__init__.py +0 -0
  49. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/helpers/audit.py +0 -0
  50. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/helpers/cron.py +0 -0
  51. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/helpers/db_analysis.py +0 -0
  52. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/helpers/get_account.py +0 -0
  53. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/helpers/host_maintenance.py +0 -0
  54. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/helpers/inventory.py +0 -0
  55. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/helpers/label_hash.py +0 -0
  56. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/helpers/label_history.py +0 -0
  57. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/helpers/local_config_file.py +0 -0
  58. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/helpers/local_config_presets.py +0 -0
  59. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/helpers/mongo_keys.py +0 -0
  60. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/helpers/notification_channels.py +0 -0
  61. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/helpers/notification_dispatch.py +0 -0
  62. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/helpers/plugins.py +0 -0
  63. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/helpers/retention.py +0 -0
  64. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/helpers/sates.py +0 -0
  65. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/helpers/sql.py +0 -0
  66. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/helpers/stale_indexes.py +0 -0
  67. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/helpers/syncer_jinja.py +0 -0
  68. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/helpers/tablib_formater.py +0 -0
  69. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/helpers/tests/__init__.py +0 -0
  70. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/helpers/tests/test_sql.py +0 -0
  71. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/mcp_server.py +0 -0
  72. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/models/__init__.py +0 -0
  73. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/models/account.py +0 -0
  74. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/models/config.py +0 -0
  75. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/models/cron.py +0 -0
  76. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/models/field_approval.py +0 -0
  77. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/models/forms.py +0 -0
  78. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/models/host.py +0 -0
  79. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/models/host_cleanup.py +0 -0
  80. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/models/host_inventory_tree.py +0 -0
  81. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/models/host_label_event.py +0 -0
  82. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/models/host_templates.py +0 -0
  83. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/models/notification_channel.py +0 -0
  84. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/models/notification_rule.py +0 -0
  85. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/models/notification_state.py +0 -0
  86. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/models/project.py +0 -0
  87. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/models/saved_search.py +0 -0
  88. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/models/states.py +0 -0
  89. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/module_registry.py +0 -0
  90. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/modules/__init__.py +0 -0
  91. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/modules/custom_attributes/models.py +0 -0
  92. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/modules/custom_attributes/rules.py +0 -0
  93. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/modules/custom_attributes/views.py +0 -0
  94. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/modules/debug.py +0 -0
  95. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/modules/email.py +0 -0
  96. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/modules/inventory/__init__.py +0 -0
  97. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/modules/log/command_output.py +0 -0
  98. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/modules/log/log.py +0 -0
  99. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/modules/log/models.py +0 -0
  100. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/modules/log/views.py +0 -0
  101. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/modules/plugin.py +0 -0
  102. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/modules/rule/__init__.py +0 -0
  103. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/modules/rule/filter.py +0 -0
  104. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/modules/rule/match.py +0 -0
  105. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/modules/rule/models.py +0 -0
  106. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/modules/rule/rewrite.py +0 -0
  107. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/modules/rule/rule.py +0 -0
  108. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/modules/rule/views.py +0 -0
  109. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/modules/search_parser.py +0 -0
  110. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/modules/statefile.py +0 -0
  111. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/notices/strict_certificate_verification.txt +0 -0
  112. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/__init__.py +0 -0
  113. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/ansible/__init__.py +0 -0
  114. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/ansible/admin_views.py +0 -0
  115. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/ansible/inventory.py +0 -0
  116. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/ansible/models.py +0 -0
  117. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/ansible/playbook_rules.py +0 -0
  118. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/ansible/plugin.json +0 -0
  119. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/ansible/rules.py +0 -0
  120. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/ansible/runner.py +0 -0
  121. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/ansible/seed.py +0 -0
  122. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/ansible/site_syncer.py +0 -0
  123. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/ansible/views.py +0 -0
  124. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/bmc_remedy/__init__.py +0 -0
  125. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/bmc_remedy/bmc_remedy.py +0 -0
  126. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/bmc_remedy/plugin.json +0 -0
  127. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/__init__.py +0 -0
  128. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/admin_views.py +0 -0
  129. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/bi.py +0 -0
  130. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/cmk2.py +0 -0
  131. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/cmk_rules.py +0 -0
  132. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/data_quality.py +0 -0
  133. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/dcd.py +0 -0
  134. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/downtimes.py +0 -0
  135. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/folder_attributes.py +0 -0
  136. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/groups.py +0 -0
  137. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/helpers.py +0 -0
  138. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/import_v1.py +0 -0
  139. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/import_v2.py +0 -0
  140. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/inits.py +0 -0
  141. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/inventorize.py +0 -0
  142. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/models.py +0 -0
  143. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/notification_rules.py +0 -0
  144. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/passwords.py +0 -0
  145. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/plugin.json +0 -0
  146. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/poolfolder.py +0 -0
  147. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/rule_analysis_runner.py +0 -0
  148. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/rule_passwords.py +0 -0
  149. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/rules.py +0 -0
  150. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/rulesets_catalog.py +0 -0
  151. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/sitepool.py +0 -0
  152. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/sites.py +0 -0
  153. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/syncer.py +0 -0
  154. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/tags.py +0 -0
  155. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/tests/__init__.py +0 -0
  156. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/tests/test_assign_template.py +0 -0
  157. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/tests/test_bi.py +0 -0
  158. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/tests/test_cmk2.py +0 -0
  159. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/tests/test_cmk_conditions.py +0 -0
  160. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/tests/test_data_quality.py +0 -0
  161. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/tests/test_dcd.py +0 -0
  162. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/tests/test_downtimes.py +0 -0
  163. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/tests/test_groups.py +0 -0
  164. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/tests/test_helpers.py +0 -0
  165. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/tests/test_import_v1.py +0 -0
  166. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/tests/test_import_v2.py +0 -0
  167. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/tests/test_notification_rules.py +0 -0
  168. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/tests/test_passwords.py +0 -0
  169. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/tests/test_poolfolder.py +0 -0
  170. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/tests/test_rule_analysis_runner.py +0 -0
  171. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/tests/test_rule_passwords.py +0 -0
  172. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/tests/test_rules.py +0 -0
  173. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/tests/test_sitepool.py +0 -0
  174. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/tests/test_sites.py +0 -0
  175. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/tests/test_syncer.py +0 -0
  176. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/tests/test_tags.py +0 -0
  177. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/views.py +0 -0
  178. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/cisco_dna/__init__.py +0 -0
  179. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/cisco_dna/plugin.json +0 -0
  180. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/cisco_dna/syncer.py +0 -0
  181. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/cron.py +0 -0
  182. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/csv/__init__.py +0 -0
  183. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/csv/csv.py +0 -0
  184. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/csv/plugin.json +0 -0
  185. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/file_requests.py +0 -0
  186. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/idoit/__init__.py +0 -0
  187. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/idoit/admin_views.py +0 -0
  188. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/idoit/models.py +0 -0
  189. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/idoit/plugin.json +0 -0
  190. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/idoit/rules.py +0 -0
  191. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/idoit/syncer.py +0 -0
  192. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/idoit/views.py +0 -0
  193. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/jdisc/__init__.py +0 -0
  194. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/jdisc/applications.py +0 -0
  195. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/jdisc/devices.py +0 -0
  196. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/jdisc/executables.py +0 -0
  197. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/jdisc/jdisc.py +0 -0
  198. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/jdisc/plugin.json +0 -0
  199. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/jira/__init__.py +0 -0
  200. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/jira/jira.py +0 -0
  201. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/jira/plugin.json +0 -0
  202. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/jira_cloud/__init__.py +0 -0
  203. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/jira_cloud/admin_views.py +0 -0
  204. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/jira_cloud/export.py +0 -0
  205. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/jira_cloud/jira_cloud.py +0 -0
  206. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/jira_cloud/models.py +0 -0
  207. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/jira_cloud/plugin.json +0 -0
  208. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/jira_cloud/rules.py +0 -0
  209. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/jira_cloud/schema_sync.py +0 -0
  210. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/jira_cloud/tests/__init__.py +0 -0
  211. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/jira_cloud/tests/test_attribute_value.py +0 -0
  212. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/jira_cloud/views.py +0 -0
  213. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/json/__init__.py +0 -0
  214. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/json/json.py +0 -0
  215. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/json/plugin.json +0 -0
  216. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/ldap/__init__.py +0 -0
  217. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/ldap/admin_views.py +0 -0
  218. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/ldap/ldap.py +0 -0
  219. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/ldap/plugin.json +0 -0
  220. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/ldap/views.py +0 -0
  221. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/maintenance/db_commands.py +0 -0
  222. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/maintenance/plugin.json +0 -0
  223. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/maintenance/tests/__init__.py +0 -0
  224. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/maintenance/tests/test_delete_all_hosts.py +0 -0
  225. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/maintenance/tests/test_delete_inventory.py +0 -0
  226. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/mssql/__init__.py +0 -0
  227. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/mssql/plugin.json +0 -0
  228. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/mysql/__init__.py +0 -0
  229. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/mysql/mysql.py +0 -0
  230. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/mysql/plugin.json +0 -0
  231. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/netbox/__init__.py +0 -0
  232. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/netbox/admin_views.py +0 -0
  233. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/netbox/cluster.py +0 -0
  234. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/netbox/contacts.py +0 -0
  235. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/netbox/dataflow.py +0 -0
  236. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/netbox/devices.py +0 -0
  237. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/netbox/interfaces.py +0 -0
  238. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/netbox/ips.py +0 -0
  239. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/netbox/models.py +0 -0
  240. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/netbox/netbox.py +0 -0
  241. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/netbox/networks.py +0 -0
  242. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/netbox/plugin.json +0 -0
  243. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/netbox/prefixes.py +0 -0
  244. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/netbox/rules.py +0 -0
  245. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/netbox/tests/__init__.py +0 -0
  246. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/netbox/tests/test_import_filter.py +0 -0
  247. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/netbox/utils.py +0 -0
  248. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/netbox/views.py +0 -0
  249. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/netbox/virtualmachines.py +0 -0
  250. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/prtg/__init__.py +0 -0
  251. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/prtg/plugin.json +0 -0
  252. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/prtg/prtg.py +0 -0
  253. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/pyodbc/__init__.py +0 -0
  254. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/pyodbc/plugin.json +0 -0
  255. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/pyodbc/pyodbc.py +0 -0
  256. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/rest/__init__.py +0 -0
  257. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/rest/plugin.json +0 -0
  258. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/rest/rest.py +0 -0
  259. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/rules/__init__.py +0 -0
  260. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/rules/admin_views.py +0 -0
  261. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/rules/autorules.py +0 -0
  262. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/rules/models.py +0 -0
  263. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/rules/plugin.json +0 -0
  264. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/rules/rule_definitions.py +0 -0
  265. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/rules/rule_import_export.py +0 -0
  266. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/rules/views.py +0 -0
  267. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/servicenow/__init__.py +0 -0
  268. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/servicenow/admin_views.py +0 -0
  269. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/servicenow/plugin.json +0 -0
  270. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/servicenow/syncer.py +0 -0
  271. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/servicenow/tests/__init__.py +0 -0
  272. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/servicenow/tests/test_table_request.py +0 -0
  273. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/servicenow/views.py +0 -0
  274. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/syncer_shell.py +0 -0
  275. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/vmware/__init__.py +0 -0
  276. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/vmware/admin_views.py +0 -0
  277. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/vmware/custom_attributes.py +0 -0
  278. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/vmware/models.py +0 -0
  279. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/vmware/plugin.json +0 -0
  280. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/vmware/rules.py +0 -0
  281. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/vmware/views.py +0 -0
  282. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/vmware/vmware.py +0 -0
  283. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/yml/__init__.py +0 -0
  284. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/yml/plugin.json +0 -0
  285. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/yml/yml.py +0 -0
  286. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins_cli.py +0 -0
  287. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/static/cmdbsyncer_mark.png +0 -0
  288. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/static/css/cmdbsyncer.css +0 -0
  289. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/static/favicon.png +0 -0
  290. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/static/js/Sortable.min.js +0 -0
  291. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/static/js/main.js +0 -0
  292. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/static/logo_white.png +0 -0
  293. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/static/vendor/README.md +0 -0
  294. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/static/vendor/ansible.svg +0 -0
  295. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/static/vendor/checkmk.svg +0 -0
  296. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/static/vendor/idoit.svg +0 -0
  297. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/static/vendor/jira.svg +0 -0
  298. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/static/vendor/netbox.svg +0 -0
  299. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/static/vendor/vmware.svg +0 -0
  300. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/_brand.html +0 -0
  301. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/_theme.html +0 -0
  302. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/_host_tabs.html +0 -0
  303. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/account_create.html +0 -0
  304. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/account_edit.html +0 -0
  305. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/account_field_help.html +0 -0
  306. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/account_pick_type.html +0 -0
  307. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/ansible_playbook_run.html +0 -0
  308. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/ansible_project_detail.html +0 -0
  309. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/ansible_rule_list.html +0 -0
  310. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/ansible_run_details.html +0 -0
  311. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/assign_project_form.html +0 -0
  312. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/bulk_label_form.html +0 -0
  313. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/changelog_archive.html +0 -0
  314. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/checkmk_data_quality.html +0 -0
  315. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/checkmk_rule_mngmt_list.html +0 -0
  316. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/checkmk_rule_optimization.html +0 -0
  317. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/checkmk_settings_list.html +0 -0
  318. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/checkmk_test_folder_scope.html +0 -0
  319. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/copy_as_new_form.html +0 -0
  320. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/data_quality.html +0 -0
  321. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/data_quality_lowercase_preview.html +0 -0
  322. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/file/list.html +0 -0
  323. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/file/modals/form.html +0 -0
  324. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/first_steps.html +0 -0
  325. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/host_csv_import_preview.html +0 -0
  326. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/host_details.html +0 -0
  327. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/host_edit.html +0 -0
  328. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/host_inventory_tree.html +0 -0
  329. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/host_list.html +0 -0
  330. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/host_relations_graph.html +0 -0
  331. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/host_timeline.html +0 -0
  332. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/index.html +0 -0
  333. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/ldap_search.html +0 -0
  334. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/local_config_editor.html +0 -0
  335. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/master.html +0 -0
  336. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/model/_action_picker.html +0 -0
  337. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/model/_folder_builder.html +0 -0
  338. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/model/_notification_plugin_picker.html +0 -0
  339. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/model/_ruleset_autocomplete.html +0 -0
  340. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/model/checkmk_notification_rule_create.html +0 -0
  341. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/model/checkmk_notification_rule_edit.html +0 -0
  342. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/model/checkmk_rule_create.html +0 -0
  343. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/model/checkmk_rule_edit.html +0 -0
  344. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/model/checkmk_rule_mngmt_create.html +0 -0
  345. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/model/checkmk_rule_mngmt_edit.html +0 -0
  346. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/model/clone_confirm.html +0 -0
  347. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/model/inline_list_base.html +0 -0
  348. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/module_overview.html +0 -0
  349. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/object_list.html +0 -0
  350. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/project_edit.html +0 -0
  351. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/project_import.html +0 -0
  352. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/project_import_cmk.html +0 -0
  353. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/project_list.html +0 -0
  354. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/project_overview.html +0 -0
  355. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/servicenow_query.html +0 -0
  356. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/set_account_form.html +0 -0
  357. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/set_cmk_version_form.html +0 -0
  358. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/set_template_form.html +0 -0
  359. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/api_tokens.html +0 -0
  360. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/base.html +0 -0
  361. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/change_password.html +0 -0
  362. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/csrf_error.html +0 -0
  363. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/debug.html +0 -0
  364. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/debug_host.html +0 -0
  365. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/email/newuser.html +0 -0
  366. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/email/notification.html +0 -0
  367. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/email/resetpassword.html +0 -0
  368. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/formular.html +0 -0
  369. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/login.html +0 -0
  370. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/logout_confirm.html +0 -0
  371. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/request_password.html +0 -0
  372. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/set_2fa.html +0 -0
  373. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/set_theme.html +0 -0
  374. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/themes/dracula.css +0 -0
  375. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/themes/gruvbox-dark.css +0 -0
  376. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/themes/gruvbox-light.css +0 -0
  377. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/themes/nord.css +0 -0
  378. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/themes_registry.py +0 -0
  379. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/views/_form_fields.py +0 -0
  380. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/views/_form_sections.py +0 -0
  381. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/views/account.py +0 -0
  382. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/views/account_select.py +0 -0
  383. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/views/config.py +0 -0
  384. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/views/cron.py +0 -0
  385. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/views/data_quality.py +0 -0
  386. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/views/default.py +0 -0
  387. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/views/field_approval.py +0 -0
  388. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/views/fileadmin.py +0 -0
  389. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/views/first_steps.py +0 -0
  390. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/views/host.py +0 -0
  391. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/views/host_filters.py +0 -0
  392. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/views/host_inventory_grid.py +0 -0
  393. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/views/host_renderers.py +0 -0
  394. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/views/host_widgets.py +0 -0
  395. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/views/menu_links.py +0 -0
  396. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/views/module_overview.py +0 -0
  397. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/views/notification_channel.py +0 -0
  398. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/views/notification_rule.py +0 -0
  399. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/views/project.py +0 -0
  400. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/views/saved_search.py +0 -0
  401. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/views/template_select.py +0 -0
  402. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/views/user.py +0 -0
  403. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/cmdbsyncer.egg-info/dependency_links.txt +0 -0
  404. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/cmdbsyncer.egg-info/entry_points.txt +0 -0
  405. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/cmdbsyncer.egg-info/requires.txt +0 -0
  406. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/cmdbsyncer.egg-info/top_level.txt +0 -0
  407. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/requirements-ansible-windows.txt +0 -0
  408. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/requirements-ansible.txt +0 -0
  409. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/requirements-extras.txt +0 -0
  410. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/requirements.txt +0 -0
  411. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/setup.cfg +0 -0
  412. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/syncerapi/__init__.py +0 -0
  413. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/syncerapi/v1/__init__.py +0 -0
  414. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/syncerapi/v1/core/__init__.py +0 -0
  415. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/syncerapi/v1/inventory/__init__.py +0 -0
  416. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/syncerapi/v1/rest/__init__.py +0 -0
  417. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_account_macro.py +0 -0
  418. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_api.py +0 -0
  419. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_api_csrf_invariant.py +0 -0
  420. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_cron_missing_account.py +0 -0
  421. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_csrf_config.py +0 -0
  422. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_data_quality_duplicates.py +0 -0
  423. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_default_view.py +0 -0
  424. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_disabled_row_style.py +0 -0
  425. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_folder_builder_js.py +0 -0
  426. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_global_account_presets.py +0 -0
  427. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_host_cleanup.py +0 -0
  428. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_host_label_edit.py +0 -0
  429. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_host_template_filter.py +0 -0
  430. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_host_template_resync.py +0 -0
  431. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_jinja_get_list.py +0 -0
  432. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_jinja_hash.py +0 -0
  433. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_label_history.py +0 -0
  434. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_local_config_presets.py +0 -0
  435. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_logging_config.py +0 -0
  436. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_model_indexes.py +0 -0
  437. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_mongo_keys.py +0 -0
  438. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_plugin.py +0 -0
  439. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_plugin_ssti.py +0 -0
  440. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_plugins_cli.py +0 -0
  441. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_rule.py +0 -0
  442. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_rule_export_templates.py +0 -0
  443. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_rule_filename_detect.py +0 -0
  444. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_rule_import_override.py +0 -0
  445. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_rule_match.py +0 -0
  446. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_rule_registry_complete.py +0 -0
  447. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_search_parser.py +0 -0
  448. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_security_fixes.py +0 -0
  449. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_stale_indexes.py +0 -0
  450. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_template_merge_fields.py +0 -0
  451. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_view_permission_flags.py +0 -0
  452. {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_webhook_token_hash.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cmdbsyncer
3
- Version: 4.3.2
3
+ Version: 4.3.4
4
4
  Summary: Rule-based modular synchronizer for Checkmk, Netbox, Ansible, I-DOIT, Jira CMDB and 15+ other CMDB/monitoring systems
5
5
  Author-email: Kuhn & Ruess GmbH <info@kuhn-ruess.de>
6
6
  Maintainer-email: Bastian Kuhn <mail@bastian-kuhn.de>
@@ -70,6 +70,13 @@ for _candidate in _config_candidates:
70
70
  break
71
71
  if os.getcwd() not in sys.path:
72
72
  sys.path.insert(0, os.getcwd())
73
+ # A directory named by the operator goes on the path even when it holds no
74
+ # ``local_config.py`` yet: on a container install the first boot is what
75
+ # creates that file, and ``sys self_configure`` has to be able to import it
76
+ # in the same run. An empty directory in front changes nothing otherwise —
77
+ # the import simply falls through to the next entry.
78
+ if _env_dir and _env_dir not in sys.path:
79
+ sys.path.insert(0, _env_dir)
73
80
 
74
81
  import importlib
75
82
  import pkgutil
@@ -166,8 +166,17 @@ def login(): # pylint: disable=too-many-return-statements,too-many-branches,too
166
166
  if ldap_user:
167
167
  existing_user = ldap_user
168
168
  ldap_authenticated = True
169
- except Exception: # pylint: disable=broad-exception-caught
170
- log.log("LDAP login failed", source="AUTH")
169
+ except Exception as exp: # pylint: disable=broad-exception-caught
170
+ # `log.log` already files the traceback, but it sits
171
+ # collapsed in the detail view of a single entry and reads
172
+ # like a crash report. The reason belongs in the record
173
+ # itself, next to the AUTH entries the login handler writes
174
+ # either side of it, so a list of them tells an unreachable
175
+ # server apart from a service account with the wrong
176
+ # password. The person logging in still sees the generic
177
+ # message; the directory's answer is not theirs to read.
178
+ log.log("LDAP login failed", source="AUTH",
179
+ details=[('email', email), ('error', str(exp))])
171
180
  flash('LDAP Error', 'danger')
172
181
  return render_template('login.html', **context)
173
182
 
@@ -0,0 +1 @@
1
+ BUILD_DATE=2026-09-16T11:58:47Z
@@ -1,5 +1,16 @@
1
1
  # Version 4.3
2
2
 
3
+ ## Version 4.3.4
4
+ - FIX: A user the directory created can now log in — a successful directory bind ended in a server error for anybody who has no local password, which is every user created on first login
5
+ - FIX: A directory login that fails records what went wrong, so an unreachable server, a service account with the wrong password and a group mapping naming a role that does not exist can be told apart in Settings → Log
6
+ - FIX: The License page is listed in the Settings menu again, so a license file can be uploaded without having to know the address of the page
7
+ - FIX: The License page names the path it really expects the license file at, instead of a fixed path that was wrong in every container and in most installations made with pip
8
+
9
+ ## Version 4.3.3
10
+ - FEAT: Every release is published as a ready-made container image, so a deployment can pull `ghcr.io/kuhn-ruess/cmdbsyncer:4.3.3` instead of cloning the repository and building it — `docker-compose.registry.yml` is a complete stack that uses it
11
+ - FIX: A container can keep its configuration outside the image by setting CMDBSYNCER_CONFIG_DIR to a mounted directory; without it, replacing the image regenerated the key that the stored account passwords are encrypted with and none of them could be read afterwards
12
+ - FIX: Exporting Checkmk users no longer stops with "pager address may not be null" when a user has no pager address, no mail address or no role; an empty field is sent as empty instead of as nothing, which also stops such a user from being rewritten on every export
13
+
3
14
  ## Version 4.3.2
4
15
  - FEAT: The "create missing hosts" card of the Checkmk data quality check has a lowercase toggle, so host names the uppercase check reported can be put into the syncer in lowercase — the appended domain included
5
16
  - FIX: A cronjob whose account is gone — for example after importing rules without the matching accounts — no longer breaks the Cronjob page; the group is listed with a note and can be opened to assign the right account
@@ -5,11 +5,19 @@ Populated by `load_package()` from the optional `cmdbsyncer_enterprise` package.
5
5
  If the package is not installed (or its license check fails), the registry
6
6
  stays empty and all hooks become no-ops — OSS code continues to work.
7
7
 
8
+ The published Docker image ships the package on every install, licensed or
9
+ not, so a customer who buys a license only has to drop in `license.jwt`.
10
+ An install without one must therefore look exactly like an install without
11
+ the package: `load_package()` stays silent when there is no license to
12
+ activate, and only reports when a license is there and something went wrong
13
+ with it.
14
+
8
15
  `load_package()` must be called explicitly from the app factory *after* the
9
16
  MongoEngine `db` handle has been created, because the enterprise package
10
17
  transitively imports `application.models.*`, which depend on
11
18
  `from application import db`.
12
19
  """
20
+ import os
13
21
  import sys
14
22
  import importlib.util
15
23
 
@@ -30,7 +38,6 @@ def _report(message):
30
38
  """
31
39
  # ``./cmdbsyncer <command>`` sets CMDBSYNCER_CLI so command output isn't
32
40
  # preceded by a banner line — the web/worker processes keep the banner.
33
- import os # pylint: disable=import-outside-toplevel
34
41
  if os.environ.get("CMDBSYNCER_CLI") == "1":
35
42
  return
36
43
  global _pending_report # pylint: disable=global-statement
@@ -56,6 +63,34 @@ def emit_load_status(logger=None):
56
63
  print(f"[cmdbsyncer-enterprise] {message}", file=sys.stderr, flush=True)
57
64
 
58
65
 
66
+ def license_path():
67
+ """Return the file the enterprise package reads its license from.
68
+
69
+ Mirrors the resolution in ``cmdbsyncer_enterprise.license``: the
70
+ ``CMDBSYNCER_LICENSE`` environment variable wins, otherwise
71
+ ``license.jwt`` next to the deployment's ``local_config.py``. Resolved
72
+ here instead of asked of the package, because the question comes up
73
+ exactly when the package cannot be imported. Returns None when neither
74
+ candidate can be determined.
75
+ """
76
+ env_path = os.environ.get('CMDBSYNCER_LICENSE')
77
+ if env_path:
78
+ return env_path
79
+ try:
80
+ spec = importlib.util.find_spec('local_config')
81
+ except (ImportError, ValueError):
82
+ spec = None
83
+ if spec and spec.origin:
84
+ return os.path.join(os.path.dirname(spec.origin), 'license.jwt')
85
+ return None
86
+
87
+
88
+ def license_file_present():
89
+ """True when a license file exists where the package looks for it."""
90
+ path = license_path()
91
+ return bool(path) and os.path.isfile(path)
92
+
93
+
59
94
  def register_feature(name, hook_fn=None):
60
95
  """Enable a named feature and optionally bind an implementation function."""
61
96
  _features.add(name)
@@ -86,6 +121,13 @@ def load_package():
86
121
  load_status = 'active'
87
122
  _report("package loaded successfully")
88
123
  except Exception as exp: # pylint: disable=broad-exception-caught
124
+ if not license_file_present():
125
+ # Nothing is wrong here — this install simply has no license,
126
+ # which is the normal state for every Community Edition user of
127
+ # the Docker image. Reporting it would put a line that reads
128
+ # like a failure in front of every start they ever do.
129
+ load_status = 'inactive: no license installed'
130
+ return
89
131
  load_status = f'failed: {exp}'
90
132
  _report(
91
133
  f"package installed but failed to activate "
@@ -159,8 +159,17 @@ class User(db.Document, UserMixin):
159
159
 
160
160
  def check_password(self, password):
161
161
  """
162
- Password checker
162
+ Password checker.
163
+
164
+ A user who only ever authenticated against a directory has no local
165
+ hash at all. The login view asks every user for one before it decides
166
+ — it has to, a directory answer of "no" must still allow a local
167
+ password — so without this guard that question reached werkzeug with
168
+ None and raised, turning a successful LDAP bind into a server error.
169
+ No hash simply means no local password, which never matches.
163
170
  """
171
+ if not self.pwdhash:
172
+ return False
164
173
  return check_password_hash(self.pwdhash, password)
165
174
 
166
175
  def account_scope(self):
@@ -351,7 +351,7 @@ class TestCheckmkRuleSync(unittest.TestCase):
351
351
  'loop_over_list': False,
352
352
  'list_to_loop': '',
353
353
  'condition_label_template': '',
354
- 'condition_host': 'fmg-host01',
354
+ 'condition_host': 'host01',
355
355
  'condition_service': '',
356
356
  'condition_service_label': '',
357
357
  }
@@ -359,7 +359,7 @@ class TestCheckmkRuleSync(unittest.TestCase):
359
359
  # Owner host: HOSTNAME == condition_host → optimize path.
360
360
  self.sync.calculate_rules_of_host(
361
361
  {'agent_config:mrpe': [dict(outcome)]},
362
- {'all': {'HOSTNAME': 'fmg-host01'}})
362
+ {'all': {'HOSTNAME': 'host01'}})
363
363
  # Foreign host: HOSTNAME != condition_host → plain variant.
364
364
  self.sync.calculate_rules_of_host(
365
365
  {'agent_config:mrpe': [dict(outcome)]},
@@ -370,7 +370,7 @@ class TestCheckmkRuleSync(unittest.TestCase):
370
370
  rules = self.sync.rulsets_by_type['agent_config:mrpe']
371
371
  self.assertEqual(len(rules), 1)
372
372
  self.assertEqual(
373
- rules[0]['condition']['host_name']['match_on'], ['fmg-host01'])
373
+ rules[0]['condition']['host_name']['match_on'], ['host01'])
374
374
 
375
375
  def test_collect_rule_dedupes_without_rescanning(self):
376
376
  # Every host feeds the same list, so the duplicate check used to
@@ -420,7 +420,7 @@ class TestCheckmkRuleSync(unittest.TestCase):
420
420
  'loop_over_list': False,
421
421
  'list_to_loop': '',
422
422
  'condition_label_template': '',
423
- 'condition_host': 'fmg-host01',
423
+ 'condition_host': 'host01',
424
424
  'condition_service': '',
425
425
  'condition_service_label': '',
426
426
  })
@@ -144,7 +144,7 @@ class TestInventorizeHosts(unittest.TestCase):
144
144
  'extensions': {
145
145
  'effective_attributes': None,
146
146
  'labels': {
147
- 'piggyback_source_vc-prd-w-mgmt.services.p.rz.drv': 'yes',
147
+ 'piggyback_source_srv01.mgmt.dc1.example.com': 'yes',
148
148
  'plain_label': 'value',
149
149
  },
150
150
  },
@@ -156,9 +156,9 @@ class TestInventorizeHosts(unittest.TestCase):
156
156
  self.inv.get_attr_labels()
157
157
 
158
158
  inv = self.inv.config_inventory['host1']
159
- self.assertIn('label_piggyback_source_vc-prd-w-mgmt_services_p_rz_drv', inv)
159
+ self.assertIn('label_piggyback_source_srv01_mgmt_dc1_example_com', inv)
160
160
  self.assertNotIn(
161
- 'label_piggyback_source_vc-prd-w-mgmt.services.p.rz.drv', inv,
161
+ 'label_piggyback_source_srv01.mgmt.dc1.example.com', inv,
162
162
  )
163
163
  self.assertIn('label_plain_label', inv)
164
164
 
@@ -44,6 +44,53 @@ class TestCheckmkUserSync(unittest.TestCase):
44
44
  setattr(user, key, val)
45
45
  return user
46
46
 
47
+ @patch('application.plugins.checkmk.users.CheckmkUserMngmt')
48
+ @patch('builtins.print')
49
+ def test_a_never_filled_field_is_sent_empty_not_null(self, mock_print,
50
+ mock_mngmt):
51
+ # Checkmk answers "pager address may not be null" for every one of
52
+ # these, and a field nobody ever filled in is None on the document
53
+ user = self._make_user(pager_address=None, email=None,
54
+ disable_login=None, roles=None,
55
+ contact_groups=None, full_name=None)
56
+ mock_mngmt.objects.return_value = [user]
57
+
58
+ with patch.object(self.sync, 'request') as mock_req:
59
+ mock_req.side_effect = [({}, {'status_code': 404}),
60
+ ({'id': 'testuser'}, {})]
61
+ self.sync.export_users()
62
+
63
+ sent = mock_req.call_args_list[1][1]['data']
64
+ self.assertEqual(sent['pager_address'], '')
65
+ self.assertEqual(sent['contact_options']['email'], '')
66
+ self.assertEqual(sent['disable_login'], False)
67
+ self.assertEqual(sent['roles'], [])
68
+ self.assertEqual(sent['contactgroups'], [])
69
+ # A user without a full name is still a user Checkmk accepts
70
+ self.assertEqual(sent['fullname'], 'testuser')
71
+
72
+ @patch('application.plugins.checkmk.users.CheckmkUserMngmt')
73
+ @patch('builtins.print')
74
+ def test_an_empty_field_is_not_a_change(self, mock_print, mock_mngmt):
75
+ # Checkmk answers with the empty value, so a None on our side used
76
+ # to look different on every run and rewrote the user each time
77
+ user = self._make_user(pager_address=None, email=None)
78
+ mock_mngmt.objects.return_value = [user]
79
+ cmk_side = {
80
+ 'fullname': 'Test User', 'disable_login': False,
81
+ 'pager_address': '', 'contactgroups': ['all'],
82
+ 'roles': ['user'], 'contact_options': {'email': ''},
83
+ }
84
+
85
+ with patch.object(self.sync, 'request') as mock_req:
86
+ mock_req.side_effect = [
87
+ ({'extensions': cmk_side}, {'ETag': 'x'}),
88
+ ]
89
+ self.sync.export_users()
90
+
91
+ # Only the GET happened, nothing was written back
92
+ self.assertEqual(mock_req.call_count, 1)
93
+
47
94
  @patch('application.plugins.checkmk.users.CheckmkUserMngmt')
48
95
  @patch('builtins.print')
49
96
  def test_export_users_creates_new(self, mock_print, mock_mngmt):
@@ -31,26 +31,31 @@ class CheckmkUserSync(CMK2):
31
31
  url = f"/objects/user_config/{user.user_id}"
32
32
  cmk_user = self.request(url, method="GET")
33
33
  # ({}, {'status_code': 404})
34
+ # A field never filled in is None on the document, and the
35
+ # Checkmk API rejects null for every one of these ("pager
36
+ # address may not be null"). Checkmk itself answers with the
37
+ # empty value, so sending that is also what keeps has_changes
38
+ # from reporting a difference on every single run.
34
39
  user_template = {
35
40
  "username": user.user_id,
36
- "fullname": user.full_name,
41
+ "fullname": user.full_name or user.user_id,
37
42
  "auth_option": {
38
43
  "auth_type": "password",
39
44
  "password": user.password
40
45
  },
41
- "disable_login": user.disable_login,
46
+ "disable_login": bool(user.disable_login),
42
47
  "contact_options": {
43
- "email": user.email
48
+ "email": user.email or ''
44
49
  },
45
- "pager_address": user.pager_address,
50
+ "pager_address": user.pager_address or '',
46
51
  "idle_timeout": {
47
52
  "option": "global"
48
53
  },
49
- "roles": user.roles,
54
+ "roles": list(user.roles or []),
50
55
  #"authorized_sites": [
51
56
  # "heute"
52
57
  #],
53
- "contactgroups": user.contact_groups,
58
+ "contactgroups": list(user.contact_groups or []),
54
59
  "disable_notifications": {
55
60
  "disable": False
56
61
  },
@@ -3,6 +3,7 @@
3
3
  Maintenance Module
4
4
  """
5
5
  import os
6
+ import importlib
6
7
  import datetime
7
8
  import shutil
8
9
  import string
@@ -759,19 +760,43 @@ def migrate_accounts(old_key, new_key):
759
760
  account.set_password(password, new_key)
760
761
 
761
762
 
763
+ def _local_config_path():
764
+ """Where this deployment keeps its local_config.py.
765
+
766
+ ``$CMDBSYNCER_CONFIG_DIR`` first, matching the search order the app
767
+ factory uses to import it, then the working directory as before. The
768
+ distinction matters for container installs: the working directory is a
769
+ layer of the image and is replaced on every upgrade, so a SECRET_KEY and
770
+ CRYPTOGRAPHY_KEY written there are regenerated with the next pull —
771
+ which leaves every stored account password undecryptable. Pointing the
772
+ variable at a mounted directory keeps them.
773
+ """
774
+ config_dir = os.environ.get('CMDBSYNCER_CONFIG_DIR')
775
+ if config_dir:
776
+ os.makedirs(config_dir, exist_ok=True)
777
+ return os.path.join(config_dir, 'local_config.py')
778
+ return 'local_config.py'
779
+
780
+
762
781
  def _ensure_local_config():
763
782
  """Create a stub local_config.py if missing."""
764
783
  print("Check for local_config.py File")
765
- if os.path.isfile('local_config.py'):
784
+ path = _local_config_path()
785
+ if os.path.isfile(path):
766
786
  print(" -> Existed")
767
787
  return
768
- with open('local_config.py', 'w', encoding="utf-8") as lf:
788
+ with open(path, 'w', encoding="utf-8") as lf:
769
789
  lf.write("#!/usr/bin/env python3\n")
770
790
  lf.write('"""\nLocal Config File\n"""\n')
771
791
  lf.write("import logging\n")
772
792
  lf.write("# Only Update from here inside the config = {} object\n")
773
793
  lf.write("config = {}\n")
774
- print(" -> Created new local_config.py")
794
+ # The directory may have been put on sys.path while it was still empty
795
+ # (a fresh mounted config volume), in which case the import system has
796
+ # cached it as holding nothing. The `from local_config import config`
797
+ # further down runs in this same process.
798
+ importlib.invalidate_caches()
799
+ print(f" -> Created new local_config.py at {path}")
775
800
 
776
801
 
777
802
  def _ensure_plugins_dir():
@@ -891,13 +916,22 @@ def self_configure():
891
916
  migrate_accounts(old_key, new_key)
892
917
 
893
918
  config['CRYPTOGRAPHY_KEY'] = new_key
894
- with open('local_config.py', 'w', encoding="utf-8") as lf:
919
+ with open(_local_config_path(), 'w', encoding="utf-8") as lf:
895
920
  lf.write("#!/usr/bin/env python3\n")
896
921
  lf.write('"""\nLocal Config File\n"""\n')
897
922
  lf.write("import logging\n")
898
923
  lf.write("# Only Update from here inside the config = {} object\n")
899
924
  lf.write(f"config = {pformat(config)}\n")
900
925
 
926
+ # What was just written has to reach the running process as well. On a
927
+ # fresh install the app factory found no local_config.py to import, so
928
+ # app.config still carries BaseConfig's defaults — CRYPTOGRAPHY_KEY
929
+ # among them, as None. The migrations below this line read from
930
+ # app.config, as does anything an operator runs in the same call, and a
931
+ # key of None fails them with "no CRYPTOGRAPHY_KEY configured" while the
932
+ # file on disk has had one all along.
933
+ app.config.update(config)
934
+
901
935
  # Migrate Users
902
936
  print("Migrate users")
903
937
  User.migrate_missing_names()
@@ -93,7 +93,8 @@
93
93
  <div class="alert alert-warning mb-0" role="alert">
94
94
  <h4 class="alert-heading">Enterprise package installed, but license not active</h4>
95
95
  <p class="mb-2">
96
- Default license path: <code>/opt/cmdbsyncer/license.jwt</code>
96
+ Expected license path:
97
+ <code>{{ license_destination or 'cannot be resolved on this install' }}</code>
97
98
  (override via <code>CMDBSYNCER_LICENSE</code>).
98
99
  </p>
99
100
  {% if load_status %}
@@ -2,7 +2,6 @@
2
2
  License Information View
3
3
  """
4
4
  import importlib.util
5
- import os
6
5
  from datetime import datetime
7
6
  from pathlib import Path
8
7
 
@@ -21,13 +20,7 @@ _MAX_LICENSE_BYTES = 16 * 1024
21
20
 
22
21
  def _resolve_destination():
23
22
  """Pick the same destination the enterprise loader reads from."""
24
- env_path = os.environ.get('CMDBSYNCER_LICENSE')
25
- if env_path:
26
- return env_path
27
- spec = importlib.util.find_spec('local_config')
28
- if spec and spec.origin:
29
- return str(Path(spec.origin).parent / 'license.jwt')
30
- return None
23
+ return enterprise.license_path()
31
24
 
32
25
 
33
26
  def _enterprise_pubkey_path():
@@ -83,10 +76,13 @@ class LicenseView(BaseView):
83
76
  return current_user.is_authenticated and current_user.global_admin
84
77
 
85
78
  def is_visible(self):
86
- # Community Edition installs (no enterprise package on disk) have
87
- # nothing useful on the License page — no upload form, no feature
88
- # table — so hide the menu entry to avoid pointing admins at a
89
- # dead end. The route stays reachable via direct URL for support.
79
+ # Shown whenever the package is on disk — which, with the Docker
80
+ # image, is everywhere. That is deliberate: the page is where a
81
+ # license gets uploaded, so hiding it until a license exists leaves
82
+ # a customer who just bought one with nowhere to go. It is not a
83
+ # dead end for a Community Edition install either; it names the
84
+ # destination path, reports why nothing is active, and carries the
85
+ # upload form. `is_accessible` keeps all of it to global admins.
90
86
  return importlib.util.find_spec('cmdbsyncer_enterprise') is not None
91
87
 
92
88
  @expose('/')
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cmdbsyncer
3
- Version: 4.3.2
3
+ Version: 4.3.4
4
4
  Summary: Rule-based modular synchronizer for Checkmk, Netbox, Ansible, I-DOIT, Jira CMDB and 15+ other CMDB/monitoring systems
5
5
  Author-email: Kuhn & Ruess GmbH <info@kuhn-ruess.de>
6
6
  Maintainer-email: Bastian Kuhn <mail@bastian-kuhn.de>
@@ -408,11 +408,13 @@ syncerapi/v1/rest/__init__.py
408
408
  tests/test_account_macro.py
409
409
  tests/test_api.py
410
410
  tests/test_api_csrf_invariant.py
411
+ tests/test_config_dir.py
411
412
  tests/test_cron_missing_account.py
412
413
  tests/test_csrf_config.py
413
414
  tests/test_data_quality_duplicates.py
414
415
  tests/test_default_view.py
415
416
  tests/test_disabled_row_style.py
417
+ tests/test_enterprise_quiet.py
416
418
  tests/test_folder_builder_js.py
417
419
  tests/test_global_account_presets.py
418
420
  tests/test_host_cleanup.py
@@ -440,5 +442,8 @@ tests/test_search_parser.py
440
442
  tests/test_security_fixes.py
441
443
  tests/test_stale_indexes.py
442
444
  tests/test_template_merge_fields.py
445
+ tests/test_user_scope_smoke.py
443
446
  tests/test_view_permission_flags.py
447
+ tests/test_web_boot_smoke.py
448
+ tests/test_web_requests_smoke.py
444
449
  tests/test_webhook_token_hash.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "cmdbsyncer"
7
- version = "4.3.2"
7
+ version = "4.3.4"
8
8
  description = "Rule-based modular synchronizer for Checkmk, Netbox, Ansible, I-DOIT, Jira CMDB and 15+ other CMDB/monitoring systems"
9
9
  readme = "README.md"
10
10
  license = { text = "MIT" }
@@ -0,0 +1,112 @@
1
+ """
2
+ A container replaces /srv with every update, so a deployment that wants to
3
+ keep its SECRET_KEY and CRYPTOGRAPHY_KEY points CMDBSYNCER_CONFIG_DIR at a
4
+ mounted directory instead. Three things have to hold for that to work, and
5
+ all of them are invisible until the day somebody upgrades:
6
+
7
+ * the directory is on the import path even while it is still empty — the
8
+ first boot is what creates local_config.py in it, and `sys self_configure`
9
+ has to be able to import the file it just wrote, in that same run
10
+ * `sys self_configure` writes to that directory rather than to the working
11
+ directory it happens to be started from
12
+ * the license file is looked for next to it, so an uploaded license survives
13
+ the upgrade as well
14
+
15
+ The real import order only exists in a fresh interpreter, so these run in a
16
+ subprocess. The working directory is deliberately a *different* scratch
17
+ directory than the config directory — with the two pointing at the same
18
+ place, a path that quietly fell back to the working directory would pass.
19
+ """
20
+ import os
21
+ import subprocess
22
+ import sys
23
+ import tempfile
24
+ import unittest
25
+
26
+ _REPO_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
27
+
28
+
29
+ def _run(snippet, seed_local_config=None):
30
+ """Run `snippet` with CMDBSYNCER_CONFIG_DIR set, from an unrelated cwd.
31
+
32
+ `seed_local_config` is written into the config directory beforehand;
33
+ without it the directory stays empty, which is the first-boot state.
34
+ `{config_dir}` is substituted in the snippet.
35
+ """
36
+ with tempfile.TemporaryDirectory() as config_dir, \
37
+ tempfile.TemporaryDirectory() as workdir:
38
+ if seed_local_config is not None:
39
+ with open(os.path.join(config_dir, 'local_config.py'),
40
+ 'w', encoding='utf-8') as fh:
41
+ fh.write(seed_local_config)
42
+ env = dict(os.environ)
43
+ env['PYTHONPATH'] = _REPO_ROOT
44
+ # CLI mode keeps the import light — no Flask-Admin scaffolding, and
45
+ # therefore no live MongoDB needed.
46
+ env['CMDBSYNCER_CLI'] = '1'
47
+ env['CMDBSYNCER_CONFIG_DIR'] = config_dir
48
+ env['config'] = 'base'
49
+ env.pop('CMDBSYNCER_LICENSE', None)
50
+ return subprocess.run(
51
+ [sys.executable, '-c', snippet.replace('{config_dir}', config_dir)],
52
+ cwd=workdir, env=env, capture_output=True, text=True, check=False,
53
+ )
54
+
55
+
56
+ class TestEmptyConfigDirIsImportable(unittest.TestCase):
57
+ """The first boot happens before local_config.py exists anywhere."""
58
+
59
+ def test_directory_is_on_the_path(self):
60
+ """An empty config directory is still an import location."""
61
+ result = _run(
62
+ "import sys\n"
63
+ "import application\n"
64
+ "print('ON_PATH', '{config_dir}' in sys.path)\n"
65
+ )
66
+ self.assertEqual(result.returncode, 0, result.stderr)
67
+ self.assertIn('ON_PATH True', result.stdout)
68
+
69
+
70
+ class TestConfigDirWins(unittest.TestCase):
71
+ """Config belongs in the mounted directory, not in the image layer."""
72
+
73
+ def test_self_configure_writes_to_the_config_dir(self):
74
+ """The generated keys land in the mounted directory."""
75
+ result = _run(
76
+ "import os\n"
77
+ "from application.plugins.maintenance import _local_config_path\n"
78
+ "expected = os.path.join(os.environ['CMDBSYNCER_CONFIG_DIR'],\n"
79
+ " 'local_config.py')\n"
80
+ "print('MATCHES', _local_config_path() == expected)\n"
81
+ "print('NOT_CWD', _local_config_path() != 'local_config.py')\n",
82
+ seed_local_config="config = {}\n",
83
+ )
84
+ self.assertIn('NOT_CWD True', result.stdout)
85
+ self.assertEqual(result.returncode, 0, result.stderr)
86
+ self.assertIn('MATCHES True', result.stdout)
87
+
88
+ def test_the_settings_are_read_from_there(self):
89
+ """And the app reads its configuration back from the same place."""
90
+ result = _run(
91
+ "from application import app\n"
92
+ "print('MARKER', app.config['MARKER'])\n",
93
+ seed_local_config="config = {'MARKER': 'from-the-config-dir'}\n",
94
+ )
95
+ self.assertEqual(result.returncode, 0, result.stderr)
96
+ self.assertIn('MARKER from-the-config-dir', result.stdout)
97
+
98
+ def test_the_license_is_looked_for_next_to_it(self):
99
+ """An uploaded license survives the upgrade along with it."""
100
+ result = _run(
101
+ "from application import enterprise\n"
102
+ "print('LICENSE', enterprise.license_path())\n",
103
+ seed_local_config="config = {}\n",
104
+ )
105
+ self.assertEqual(result.returncode, 0, result.stderr)
106
+ license_path = result.stdout.split('LICENSE ')[1].strip()
107
+ self.assertTrue(license_path.endswith('/license.jwt'), license_path)
108
+ self.assertNotEqual(os.path.dirname(license_path), os.getcwd())
109
+
110
+
111
+ if __name__ == '__main__':
112
+ unittest.main()