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.
- {cmdbsyncer-4.3.2/cmdbsyncer.egg-info → cmdbsyncer-4.3.4}/PKG-INFO +1 -1
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/__init__.py +7 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/auth/views.py +11 -2
- cmdbsyncer-4.3.4/application/buildinfo.txt +1 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/changelog/v4.3.md +11 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/enterprise.py +43 -1
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/models/user.py +10 -1
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/tests/test_cmk_rules.py +4 -4
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/tests/test_inventorize.py +3 -3
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/tests/test_users.py +47 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/users.py +11 -6
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/maintenance/__init__.py +38 -4
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/license_info.html +2 -1
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/views/license.py +8 -12
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4/cmdbsyncer.egg-info}/PKG-INFO +1 -1
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/cmdbsyncer.egg-info/SOURCES.txt +5 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/pyproject.toml +1 -1
- cmdbsyncer-4.3.4/tests/test_config_dir.py +112 -0
- cmdbsyncer-4.3.4/tests/test_enterprise_quiet.py +145 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_regex_condition_limits.py +1 -1
- cmdbsyncer-4.3.4/tests/test_user_scope_smoke.py +232 -0
- cmdbsyncer-4.3.4/tests/test_web_boot_smoke.py +54 -0
- cmdbsyncer-4.3.4/tests/test_web_requests_smoke.py +122 -0
- cmdbsyncer-4.3.2/application/buildinfo.txt +0 -1
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/LICENSE +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/README.md +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/_version.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/api/__init__.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/api/inventory.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/api/objects.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/api/rules.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/api/syncer.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/api/views.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/changelog/.pages +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/changelog/v3.10.md +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/changelog/v3.11.md +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/changelog/v3.12.md +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/changelog/v3.5.md +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/changelog/v3.7.md +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/changelog/v3.8.md +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/changelog/v3.9.md +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/changelog/v4.0.md +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/changelog/v4.1.md +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/changelog/v4.2.md +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/cli.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/config.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/docu_links.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/helpers/__init__.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/helpers/audit.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/helpers/cron.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/helpers/db_analysis.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/helpers/get_account.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/helpers/host_maintenance.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/helpers/inventory.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/helpers/label_hash.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/helpers/label_history.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/helpers/local_config_file.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/helpers/local_config_presets.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/helpers/mongo_keys.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/helpers/notification_channels.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/helpers/notification_dispatch.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/helpers/plugins.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/helpers/retention.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/helpers/sates.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/helpers/sql.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/helpers/stale_indexes.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/helpers/syncer_jinja.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/helpers/tablib_formater.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/helpers/tests/__init__.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/helpers/tests/test_sql.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/mcp_server.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/models/__init__.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/models/account.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/models/config.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/models/cron.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/models/field_approval.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/models/forms.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/models/host.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/models/host_cleanup.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/models/host_inventory_tree.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/models/host_label_event.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/models/host_templates.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/models/notification_channel.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/models/notification_rule.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/models/notification_state.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/models/project.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/models/saved_search.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/models/states.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/module_registry.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/modules/__init__.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/modules/custom_attributes/models.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/modules/custom_attributes/rules.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/modules/custom_attributes/views.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/modules/debug.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/modules/email.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/modules/inventory/__init__.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/modules/log/command_output.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/modules/log/log.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/modules/log/models.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/modules/log/views.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/modules/plugin.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/modules/rule/__init__.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/modules/rule/filter.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/modules/rule/match.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/modules/rule/models.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/modules/rule/rewrite.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/modules/rule/rule.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/modules/rule/views.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/modules/search_parser.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/modules/statefile.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/notices/strict_certificate_verification.txt +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/__init__.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/ansible/__init__.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/ansible/admin_views.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/ansible/inventory.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/ansible/models.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/ansible/playbook_rules.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/ansible/plugin.json +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/ansible/rules.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/ansible/runner.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/ansible/seed.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/ansible/site_syncer.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/ansible/views.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/bmc_remedy/__init__.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/bmc_remedy/bmc_remedy.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/bmc_remedy/plugin.json +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/__init__.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/admin_views.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/bi.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/cmk2.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/cmk_rules.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/data_quality.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/dcd.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/downtimes.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/folder_attributes.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/groups.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/helpers.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/import_v1.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/import_v2.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/inits.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/inventorize.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/models.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/notification_rules.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/passwords.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/plugin.json +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/poolfolder.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/rule_analysis_runner.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/rule_passwords.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/rules.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/rulesets_catalog.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/sitepool.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/sites.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/syncer.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/tags.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/tests/__init__.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/tests/test_assign_template.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/tests/test_bi.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/tests/test_cmk2.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/tests/test_cmk_conditions.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/tests/test_data_quality.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/tests/test_dcd.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/tests/test_downtimes.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/tests/test_groups.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/tests/test_helpers.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/tests/test_import_v1.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/tests/test_import_v2.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/tests/test_notification_rules.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/tests/test_passwords.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/tests/test_poolfolder.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/tests/test_rule_analysis_runner.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/tests/test_rule_passwords.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/tests/test_rules.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/tests/test_sitepool.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/tests/test_sites.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/tests/test_syncer.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/tests/test_tags.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/checkmk/views.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/cisco_dna/__init__.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/cisco_dna/plugin.json +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/cisco_dna/syncer.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/cron.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/csv/__init__.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/csv/csv.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/csv/plugin.json +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/file_requests.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/idoit/__init__.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/idoit/admin_views.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/idoit/models.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/idoit/plugin.json +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/idoit/rules.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/idoit/syncer.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/idoit/views.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/jdisc/__init__.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/jdisc/applications.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/jdisc/devices.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/jdisc/executables.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/jdisc/jdisc.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/jdisc/plugin.json +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/jira/__init__.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/jira/jira.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/jira/plugin.json +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/jira_cloud/__init__.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/jira_cloud/admin_views.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/jira_cloud/export.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/jira_cloud/jira_cloud.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/jira_cloud/models.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/jira_cloud/plugin.json +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/jira_cloud/rules.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/jira_cloud/schema_sync.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/jira_cloud/tests/__init__.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/jira_cloud/tests/test_attribute_value.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/jira_cloud/views.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/json/__init__.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/json/json.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/json/plugin.json +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/ldap/__init__.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/ldap/admin_views.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/ldap/ldap.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/ldap/plugin.json +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/ldap/views.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/maintenance/db_commands.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/maintenance/plugin.json +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/maintenance/tests/__init__.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/maintenance/tests/test_delete_all_hosts.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/maintenance/tests/test_delete_inventory.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/mssql/__init__.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/mssql/plugin.json +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/mysql/__init__.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/mysql/mysql.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/mysql/plugin.json +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/netbox/__init__.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/netbox/admin_views.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/netbox/cluster.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/netbox/contacts.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/netbox/dataflow.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/netbox/devices.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/netbox/interfaces.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/netbox/ips.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/netbox/models.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/netbox/netbox.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/netbox/networks.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/netbox/plugin.json +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/netbox/prefixes.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/netbox/rules.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/netbox/tests/__init__.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/netbox/tests/test_import_filter.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/netbox/utils.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/netbox/views.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/netbox/virtualmachines.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/prtg/__init__.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/prtg/plugin.json +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/prtg/prtg.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/pyodbc/__init__.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/pyodbc/plugin.json +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/pyodbc/pyodbc.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/rest/__init__.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/rest/plugin.json +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/rest/rest.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/rules/__init__.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/rules/admin_views.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/rules/autorules.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/rules/models.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/rules/plugin.json +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/rules/rule_definitions.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/rules/rule_import_export.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/rules/views.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/servicenow/__init__.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/servicenow/admin_views.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/servicenow/plugin.json +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/servicenow/syncer.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/servicenow/tests/__init__.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/servicenow/tests/test_table_request.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/servicenow/views.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/syncer_shell.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/vmware/__init__.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/vmware/admin_views.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/vmware/custom_attributes.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/vmware/models.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/vmware/plugin.json +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/vmware/rules.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/vmware/views.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/vmware/vmware.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/yml/__init__.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/yml/plugin.json +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins/yml/yml.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/plugins_cli.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/static/cmdbsyncer_mark.png +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/static/css/cmdbsyncer.css +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/static/favicon.png +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/static/js/Sortable.min.js +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/static/js/main.js +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/static/logo_white.png +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/static/vendor/README.md +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/static/vendor/ansible.svg +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/static/vendor/checkmk.svg +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/static/vendor/idoit.svg +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/static/vendor/jira.svg +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/static/vendor/netbox.svg +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/static/vendor/vmware.svg +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/_brand.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/_theme.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/_host_tabs.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/account_create.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/account_edit.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/account_field_help.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/account_pick_type.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/ansible_playbook_run.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/ansible_project_detail.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/ansible_rule_list.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/ansible_run_details.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/assign_project_form.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/bulk_label_form.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/changelog_archive.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/checkmk_data_quality.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/checkmk_rule_mngmt_list.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/checkmk_rule_optimization.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/checkmk_settings_list.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/checkmk_test_folder_scope.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/copy_as_new_form.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/data_quality.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/data_quality_lowercase_preview.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/file/list.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/file/modals/form.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/first_steps.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/host_csv_import_preview.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/host_details.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/host_edit.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/host_inventory_tree.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/host_list.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/host_relations_graph.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/host_timeline.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/index.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/ldap_search.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/local_config_editor.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/master.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/model/_action_picker.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/model/_folder_builder.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/model/_notification_plugin_picker.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/model/_ruleset_autocomplete.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/model/checkmk_notification_rule_create.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/model/checkmk_notification_rule_edit.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/model/checkmk_rule_create.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/model/checkmk_rule_edit.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/model/checkmk_rule_mngmt_create.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/model/checkmk_rule_mngmt_edit.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/model/clone_confirm.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/model/inline_list_base.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/module_overview.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/object_list.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/project_edit.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/project_import.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/project_import_cmk.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/project_list.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/project_overview.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/servicenow_query.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/set_account_form.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/set_cmk_version_form.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/admin/set_template_form.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/api_tokens.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/base.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/change_password.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/csrf_error.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/debug.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/debug_host.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/email/newuser.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/email/notification.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/email/resetpassword.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/formular.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/login.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/logout_confirm.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/request_password.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/set_2fa.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/templates/set_theme.html +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/themes/dracula.css +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/themes/gruvbox-dark.css +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/themes/gruvbox-light.css +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/themes/nord.css +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/themes_registry.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/views/_form_fields.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/views/_form_sections.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/views/account.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/views/account_select.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/views/config.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/views/cron.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/views/data_quality.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/views/default.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/views/field_approval.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/views/fileadmin.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/views/first_steps.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/views/host.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/views/host_filters.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/views/host_inventory_grid.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/views/host_renderers.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/views/host_widgets.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/views/menu_links.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/views/module_overview.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/views/notification_channel.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/views/notification_rule.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/views/project.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/views/saved_search.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/views/template_select.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/application/views/user.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/cmdbsyncer.egg-info/dependency_links.txt +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/cmdbsyncer.egg-info/entry_points.txt +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/cmdbsyncer.egg-info/requires.txt +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/cmdbsyncer.egg-info/top_level.txt +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/requirements-ansible-windows.txt +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/requirements-ansible.txt +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/requirements-extras.txt +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/requirements.txt +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/setup.cfg +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/syncerapi/__init__.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/syncerapi/v1/__init__.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/syncerapi/v1/core/__init__.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/syncerapi/v1/inventory/__init__.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/syncerapi/v1/rest/__init__.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_account_macro.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_api.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_api_csrf_invariant.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_cron_missing_account.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_csrf_config.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_data_quality_duplicates.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_default_view.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_disabled_row_style.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_folder_builder_js.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_global_account_presets.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_host_cleanup.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_host_label_edit.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_host_template_filter.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_host_template_resync.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_jinja_get_list.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_jinja_hash.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_label_history.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_local_config_presets.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_logging_config.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_model_indexes.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_mongo_keys.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_plugin.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_plugin_ssti.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_plugins_cli.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_rule.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_rule_export_templates.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_rule_filename_detect.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_rule_import_override.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_rule_match.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_rule_registry_complete.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_search_parser.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_security_fixes.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_stale_indexes.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_template_merge_fields.py +0 -0
- {cmdbsyncer-4.3.2 → cmdbsyncer-4.3.4}/tests/test_view_permission_flags.py +0 -0
- {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.
|
|
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
|
|
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': '
|
|
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': '
|
|
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'], ['
|
|
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': '
|
|
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
|
-
'
|
|
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('
|
|
159
|
+
self.assertIn('label_piggyback_source_srv01_mgmt_dc1_example_com', inv)
|
|
160
160
|
self.assertNotIn(
|
|
161
|
-
'
|
|
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
|
-
|
|
784
|
+
path = _local_config_path()
|
|
785
|
+
if os.path.isfile(path):
|
|
766
786
|
print(" -> Existed")
|
|
767
787
|
return
|
|
768
|
-
with open(
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
#
|
|
87
|
-
#
|
|
88
|
-
#
|
|
89
|
-
#
|
|
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.
|
|
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.
|
|
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()
|