diff --git a/.bandit-baseline.json b/.bandit-baseline.json new file mode 100644 index 00000000..26c930b0 --- /dev/null +++ b/.bandit-baseline.json @@ -0,0 +1,2334 @@ +{ + "errors": [], + "generated_at": "2026-07-07T04:52:03Z", + "metrics": { + "_totals": { + "CONFIDENCE.HIGH": 75, + "CONFIDENCE.LOW": 15, + "CONFIDENCE.MEDIUM": 8, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 11, + "SEVERITY.LOW": 65, + "SEVERITY.MEDIUM": 22, + "SEVERITY.UNDEFINED": 0, + "loc": 18404, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/EmailValidator.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 29, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/PasswordValidator.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 10, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/UsernameValidator.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 20, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/__init__.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 2, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/app.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 1, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 1, + "SEVERITY.UNDEFINED": 0, + "loc": 435, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/blueprints/__init__.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 0, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/blueprints/cli.py": { + "CONFIDENCE.HIGH": 9, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 1, + "SEVERITY.LOW": 8, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 98, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/blueprints/marti_api/__init__.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 26, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/blueprints/marti_api/certificate_enrollment_api.py": { + "CONFIDENCE.HIGH": 1, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 1, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 195, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/blueprints/marti_api/citrap_api.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 13, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/blueprints/marti_api/contacts_marti_api.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 25, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/blueprints/marti_api/cot_marti_api.py": { + "CONFIDENCE.HIGH": 2, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 1, + "SEVERITY.MEDIUM": 1, + "SEVERITY.UNDEFINED": 0, + "loc": 70, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/blueprints/marti_api/data_package_marti_api.py": { + "CONFIDENCE.HIGH": 2, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 1, + "SEVERITY.LOW": 1, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 384, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/blueprints/marti_api/device_profile_marti_api.py": { + "CONFIDENCE.HIGH": 1, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 1, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 236, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/blueprints/marti_api/group_marti_api.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 424, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/blueprints/marti_api/marti_api.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 138, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/blueprints/marti_api/mission_marti_api.py": { + "CONFIDENCE.HIGH": 2, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 1, + "SEVERITY.MEDIUM": 1, + "SEVERITY.UNDEFINED": 0, + "loc": 1893, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/blueprints/marti_api/video_marti_api.py": { + "CONFIDENCE.HIGH": 2, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 1, + "SEVERITY.MEDIUM": 1, + "SEVERITY.UNDEFINED": 0, + "loc": 201, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/blueprints/ots_api/__init__.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 42, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/blueprints/ots_api/api.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 480, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/blueprints/ots_api/casevac_api.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 134, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/blueprints/ots_api/data_package_api.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 139, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/blueprints/ots_api/device_profile_api.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 81, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/blueprints/ots_api/eud_stats_api.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 16, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/blueprints/ots_api/group_api.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 401, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/blueprints/ots_api/language_api.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 30, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/blueprints/ots_api/ldap_api.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 56, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/blueprints/ots_api/marker_api.py": { + "CONFIDENCE.HIGH": 1, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 1, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 315, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/blueprints/ots_api/mediamtx_api.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 10, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 10, + "SEVERITY.UNDEFINED": 0, + "loc": 496, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/blueprints/ots_api/meshtastic_api.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 161, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/blueprints/ots_api/mission_api.py": { + "CONFIDENCE.HIGH": 1, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 1, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 2, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 357, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/blueprints/ots_api/package_api.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 246, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/blueprints/ots_api/plugin_api.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 109, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/blueprints/ots_api/scheduler_api.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 89, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/blueprints/ots_api/tak_gov_link_api.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 272, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/blueprints/ots_api/token_api.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 182, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/blueprints/ots_api/user_api.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 545, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/blueprints/ots_api/video_api.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 90, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/blueprints/ots_socketio.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 32, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/blueprints/scheduled_jobs.py": { + "CONFIDENCE.HIGH": 1, + "CONFIDENCE.LOW": 4, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 1, + "SEVERITY.MEDIUM": 4, + "SEVERITY.UNDEFINED": 0, + "loc": 353, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/ca_config.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 63, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/certificate_authority.py": { + "CONFIDENCE.HIGH": 16, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 9, + "SEVERITY.LOW": 6, + "SEVERITY.MEDIUM": 1, + "SEVERITY.UNDEFINED": 0, + "loc": 455, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/controllers/__init__.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 0, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/controllers/meshtastic_controller.py": { + "CONFIDENCE.HIGH": 1, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 1, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 641, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/controllers/rabbitmq_client.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 42, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/cot_parser/__init__.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 0, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/cot_parser/cot_parser.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 1189, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/defaultconfig.py": { + "CONFIDENCE.HIGH": 1, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 4, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 4, + "SEVERITY.MEDIUM": 1, + "SEVERITY.UNDEFINED": 0, + "loc": 230, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/eud_handler/EudHandler.py": { + "CONFIDENCE.HIGH": 3, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 1, + "SEVERITY.MEDIUM": 2, + "SEVERITY.UNDEFINED": 0, + "loc": 652, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/eud_handler/EudHandlerSSL.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 25, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/eud_handler/EudServer.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 28, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/eud_handler/EudServerSSL.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 49, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/eud_handler/EudServerUdp.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 27, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/eud_handler/__init__.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 0, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/eud_handler/eud_handler.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 144, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/extensions.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 17, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/forms/MediaMTXGlobalConfig.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 66, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/forms/MediaMTXPathConfig.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 84, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/forms/__init__.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 0, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/forms/casevac_form.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 47, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/forms/data_package_form.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 8, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/forms/device_profile_form.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 13, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/forms/marker_form.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 19, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/forms/package_form.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 24, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/forms/point_form.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 16, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/forms/zmist_form.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 10, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/functions.py": { + "CONFIDENCE.HIGH": 1, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 1, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 173, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/logo.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 15, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/migrations/env.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 59, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/migrations/versions/00442761c803_added_mission_guid_to_missionrole_and_.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 28, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/migrations/versions/00546817d518_added_uid_column_to_cot_table.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 17, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/migrations/versions/1041fae84708_added_eud_stats_table.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 34, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/migrations/versions/14e268184cc5_added_mission_logs_table.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 33, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/migrations/versions/21fb5a21f356_fixed_mission_changes_and_mission_uids_.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 29, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/migrations/versions/298430e7849d_fixed_video_streams_table.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 33, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/migrations/versions/2b1863a985a6_added_groups_missions_table.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 28, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/migrations/versions/2b5bddd207ae_added_some_cascades.py": { + "CONFIDENCE.HIGH": 15, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 15, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 184, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/migrations/versions/34d5df698b81_added_publish_time_to_packages_table.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 28, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/migrations/versions/34dc96ee805b_changed_device_profile_table.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 27, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/migrations/versions/35a075531973_updated_missionlogentry.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 17, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/migrations/versions/3a7ea7ead17b_added_casevac_fields.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 19, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/migrations/versions/414b87c32cc2_added_device_profile_and_package_tables.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 60, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/migrations/versions/4c7909c34d4e_initial_migration.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 467, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/migrations/versions/4f0173cdb93b_added_mission_change_id_column_to_.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 21, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/migrations/versions/591a98184047_added_id_column_to_device_profiles.py": { + "CONFIDENCE.HIGH": 1, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 1, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 39, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/migrations/versions/5d06227dea50_added_data_sync_tables.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 103, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/migrations/versions/61c7cfea0c86_added_eud_uid_to_device_profiles_table_.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 20, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/migrations/versions/6665d030f187_added_last_meshtastic_publish_to_euds_.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 17, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/migrations/versions/6a7929c07690_altered_foreign_key_on_device_profiles.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 17, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/migrations/versions/6af2256c568d_set_install_on_enrollment_and_.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 37, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/migrations/versions/795ebb9262d8_more_cascades.py": { + "CONFIDENCE.HIGH": 8, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 8, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 111, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/migrations/versions/7e9f5d2c193d_changed_phone_number_column_to_.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 33, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/migrations/versions/807c3ca8e7d0_added_mission_uids_table.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 48, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/migrations/versions/85dbe0a7dcc1_made_cot_sender_callsign_nullable.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 21, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/migrations/versions/8787888a028f_fixes_to_support_mariadb.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 49, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/migrations/versions/8d6f811f4fd7_added_fields_for_atak_plugin_versions.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 20, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/migrations/versions/ab719ee9b322_updated_groups_users_table.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 22, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/migrations/versions/b0c97a4ce0df_added_distro_column_to_plugin_table.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 19, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/migrations/versions/bde915ea136e_added_mission_logs_table.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 35, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/migrations/versions/c9fa07339363_fixes_for_the_eud_stats_table.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 87, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/migrations/versions/d1f5df78eace_more_data_sync_stuff.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 54, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/migrations/versions/d31bff4a15c7_added_mission_name_to_cot_table.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 19, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/migrations/versions/d4cc3d4afdb9_added_groups_table.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 26, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/migrations/versions/d68964dab66b_added_tokens_table.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 33, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/migrations/versions/d91957bb59a0_meshtastic_support.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 63, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/migrations/versions/e8bd877719e2_update_for_group_support.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 64, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/migrations/versions/eaf2af6f6b22_removed_unique_constraint_on_atak_.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 20, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/migrations/versions/f107b45529ba_fixes_for_the_packages_table_added_.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 64, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/migrations/versions/f2adbb61ff2f_added_type_field_to_missioninvitation.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 21, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/migrations/versions/f310052349cb_added_plugins_table.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 24, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/migrations/versions/f6dfc571d31c_added_columns_to_mission_invtations_.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 19, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/models/APSchedulerJobs.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 10, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/models/Alert.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 44, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/models/Base.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 3, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/models/CasEvac.py": { + "CONFIDENCE.HIGH": 1, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 1, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 340, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/models/Certificate.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 52, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/models/Chatrooms.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 28, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/models/ChatroomsUids.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 13, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/models/CoT.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 77, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/models/DataPackage.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 60, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/models/DeviceProfiles.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 50, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/models/EUD.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 89, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/models/EUDStats.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 62, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/models/GeoChat.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 32, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/models/Group.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 97, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/models/GroupMission.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 20, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/models/GroupUser.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 36, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/models/Icon.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 48, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/models/Marker.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 79, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/models/Meshtastic.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 106, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/models/Mission.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 134, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/models/MissionChange.py": { + "CONFIDENCE.HIGH": 1, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 1, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 179, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/models/MissionContent.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 58, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/models/MissionContentMission.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 14, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/models/MissionInvitation.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 65, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/models/MissionLogEntry.py": { + "CONFIDENCE.HIGH": 1, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 1, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 87, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/models/MissionRole.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 1, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 1, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 65, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/models/MissionUID.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 55, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/models/Packages.py": { + "CONFIDENCE.HIGH": 1, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 1, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 109, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/models/Plugins.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 13, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/models/Point.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 87, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/models/RBLine.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 101, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/models/Team.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 43, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/models/Token.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 116, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/models/VideoRecording.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 69, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/models/VideoStream.py": { + "CONFIDENCE.HIGH": 1, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 1, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 152, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/models/WebAuthn.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 4, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/models/ZMIST.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 35, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/models/__init__.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 0, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/models/role.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 14, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/models/user.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 46, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/mumble/__init__.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 0, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/mumble/mumble_authenticator.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 101, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/mumble/mumble_ice_app.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 2, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 2, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 151, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/plugins/BasePlugin.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 14, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/plugins/Plugin.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 38, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/plugins/PluginManager.py": { + "CONFIDENCE.HIGH": 2, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 2, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 251, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/plugins/__init__.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 0, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/proto/__init__.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 0, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/proto/atak_pb2.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 118, + "nosec": 0, + "skipped_tests": 0 + }, + "opentakserver/sql_jobstore.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 8, + "nosec": 0, + "skipped_tests": 0 + } + }, + "results": [ + { + "code": "118 raise RuntimeError(\"extract command failed\")\n119 if os.system(\"pybabel init -i messages.pot -d translations -l \" + lang):\n120 raise RuntimeError(\"init command failed\")\n", + "col_offset": 7, + "end_col_offset": 75, + "filename": "opentakserver/blueprints/cli.py", + "issue_confidence": "HIGH", + "issue_cwe": { + "id": 78, + "link": "https://cwe.mitre.org/data/definitions/78.html" + }, + "issue_severity": "HIGH", + "issue_text": "Starting a process with a shell, possible injection detected, security issue.", + "line_number": 119, + "line_range": [ + 119 + ], + "more_info": "https://bandit.readthedocs.io/en/1.8.0/plugins/b605_start_process_with_a_shell.html", + "test_id": "B605", + "test_name": "start_process_with_a_shell" + }, + { + "code": "113 # Use the md5 of the uploaded file as its folder name in the data package zip\n114 md5 = hashlib.md5()\n115 try:\n", + "col_offset": 10, + "end_col_offset": 23, + "filename": "opentakserver/blueprints/marti_api/data_package_marti_api.py", + "issue_confidence": "HIGH", + "issue_cwe": { + "id": 327, + "link": "https://cwe.mitre.org/data/definitions/327.html" + }, + "issue_severity": "HIGH", + "issue_text": "Use of weak MD5 hash for security. Consider usedforsecurity=False", + "line_number": 114, + "line_range": [ + 114 + ], + "more_info": "https://bandit.readthedocs.io/en/1.8.0/plugins/b324_hashlib.html", + "test_id": "B324", + "test_name": "hashlib" + }, + { + "code": "49 \n50 exit_code = subprocess.call(command, shell=True)\n51 \n", + "col_offset": 24, + "end_col_offset": 60, + "filename": "opentakserver/certificate_authority.py", + "issue_confidence": "HIGH", + "issue_cwe": { + "id": 78, + "link": "https://cwe.mitre.org/data/definitions/78.html" + }, + "issue_severity": "HIGH", + "issue_text": "subprocess call with shell=True identified, security issue.", + "line_number": 50, + "line_range": [ + 50 + ], + "more_info": "https://bandit.readthedocs.io/en/1.8.0/plugins/b602_subprocess_popen_with_shell_equals_true.html", + "test_id": "B602", + "test_name": "subprocess_popen_with_shell_equals_true" + }, + { + "code": "62 \n63 exit_code = subprocess.call(command, shell=True)\n64 \n", + "col_offset": 24, + "end_col_offset": 60, + "filename": "opentakserver/certificate_authority.py", + "issue_confidence": "HIGH", + "issue_cwe": { + "id": 78, + "link": "https://cwe.mitre.org/data/definitions/78.html" + }, + "issue_severity": "HIGH", + "issue_text": "subprocess call with shell=True identified, security issue.", + "line_number": 63, + "line_range": [ + 63 + ], + "more_info": "https://bandit.readthedocs.io/en/1.8.0/plugins/b602_subprocess_popen_with_shell_equals_true.html", + "test_id": "B602", + "test_name": "subprocess_popen_with_shell_equals_true" + }, + { + "code": "86 \n87 exit_code = subprocess.call(command, shell=True)\n88 \n", + "col_offset": 24, + "end_col_offset": 60, + "filename": "opentakserver/certificate_authority.py", + "issue_confidence": "HIGH", + "issue_cwe": { + "id": 78, + "link": "https://cwe.mitre.org/data/definitions/78.html" + }, + "issue_severity": "HIGH", + "issue_text": "subprocess call with shell=True identified, security issue.", + "line_number": 87, + "line_range": [ + 87 + ], + "more_info": "https://bandit.readthedocs.io/en/1.8.0/plugins/b602_subprocess_popen_with_shell_equals_true.html", + "test_id": "B602", + "test_name": "subprocess_popen_with_shell_equals_true" + }, + { + "code": "107 \n108 exit_code = subprocess.call(command, shell=True)\n109 \n", + "col_offset": 24, + "end_col_offset": 60, + "filename": "opentakserver/certificate_authority.py", + "issue_confidence": "HIGH", + "issue_cwe": { + "id": 78, + "link": "https://cwe.mitre.org/data/definitions/78.html" + }, + "issue_severity": "HIGH", + "issue_text": "subprocess call with shell=True identified, security issue.", + "line_number": 108, + "line_range": [ + 108 + ], + "more_info": "https://bandit.readthedocs.io/en/1.8.0/plugins/b602_subprocess_popen_with_shell_equals_true.html", + "test_id": "B602", + "test_name": "subprocess_popen_with_shell_equals_true" + }, + { + "code": "146 \n147 exit_code = subprocess.call(command, shell=True)\n148 if exit_code:\n", + "col_offset": 20, + "end_col_offset": 56, + "filename": "opentakserver/certificate_authority.py", + "issue_confidence": "HIGH", + "issue_cwe": { + "id": 78, + "link": "https://cwe.mitre.org/data/definitions/78.html" + }, + "issue_severity": "HIGH", + "issue_text": "subprocess call with shell=True identified, security issue.", + "line_number": 147, + "line_range": [ + 147 + ], + "more_info": "https://bandit.readthedocs.io/en/1.8.0/plugins/b602_subprocess_popen_with_shell_equals_true.html", + "test_id": "B602", + "test_name": "subprocess_popen_with_shell_equals_true" + }, + { + "code": "198 \n199 exit_code = subprocess.call(command, shell=True)\n200 if exit_code:\n", + "col_offset": 20, + "end_col_offset": 56, + "filename": "opentakserver/certificate_authority.py", + "issue_confidence": "HIGH", + "issue_cwe": { + "id": 78, + "link": "https://cwe.mitre.org/data/definitions/78.html" + }, + "issue_severity": "HIGH", + "issue_text": "subprocess call with shell=True identified, security issue.", + "line_number": 199, + "line_range": [ + 199 + ], + "more_info": "https://bandit.readthedocs.io/en/1.8.0/plugins/b602_subprocess_popen_with_shell_equals_true.html", + "test_id": "B602", + "test_name": "subprocess_popen_with_shell_equals_true" + }, + { + "code": "224 \n225 exit_code = subprocess.call(command, shell=True)\n226 if exit_code:\n", + "col_offset": 20, + "end_col_offset": 56, + "filename": "opentakserver/certificate_authority.py", + "issue_confidence": "HIGH", + "issue_cwe": { + "id": 78, + "link": "https://cwe.mitre.org/data/definitions/78.html" + }, + "issue_severity": "HIGH", + "issue_text": "subprocess call with shell=True identified, security issue.", + "line_number": 225, + "line_range": [ + 225 + ], + "more_info": "https://bandit.readthedocs.io/en/1.8.0/plugins/b602_subprocess_popen_with_shell_equals_true.html", + "test_id": "B602", + "test_name": "subprocess_popen_with_shell_equals_true" + }, + { + "code": "243 \n244 exit_code = subprocess.call(command, shell=True)\n245 if exit_code:\n", + "col_offset": 24, + "end_col_offset": 60, + "filename": "opentakserver/certificate_authority.py", + "issue_confidence": "HIGH", + "issue_cwe": { + "id": 78, + "link": "https://cwe.mitre.org/data/definitions/78.html" + }, + "issue_severity": "HIGH", + "issue_text": "subprocess call with shell=True identified, security issue.", + "line_number": 244, + "line_range": [ + 244 + ], + "more_info": "https://bandit.readthedocs.io/en/1.8.0/plugins/b602_subprocess_popen_with_shell_equals_true.html", + "test_id": "B602", + "test_name": "subprocess_popen_with_shell_equals_true" + }, + { + "code": "311 \n312 exit_code = subprocess.call(command, shell=True)\n313 if exit_code:\n", + "col_offset": 20, + "end_col_offset": 56, + "filename": "opentakserver/certificate_authority.py", + "issue_confidence": "HIGH", + "issue_cwe": { + "id": 78, + "link": "https://cwe.mitre.org/data/definitions/78.html" + }, + "issue_severity": "HIGH", + "issue_text": "subprocess call with shell=True identified, security issue.", + "line_number": 312, + "line_range": [ + 312 + ], + "more_info": "https://bandit.readthedocs.io/en/1.8.0/plugins/b602_subprocess_popen_with_shell_equals_true.html", + "test_id": "B602", + "test_name": "subprocess_popen_with_shell_equals_true" + } + ] +} \ No newline at end of file diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 00000000..faf45683 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @TX-RX diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 00000000..b38fcd8e --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,19 @@ +## Summary + + + +## Downstream vs upstream + +- [ ] Change also submitted upstream (PR link: ) +- [ ] Downstream-only patch (upstream declined or scope differs — reason: ) +- [ ] Fork infrastructure only (CI, docs, tooling) + +## Test plan + +- [ ] +- [ ] + +## Deploy verification + +- [ ] Verified on Azure OTS (see FORK.md deploy notes) +- [ ] N/A (docs/CI-only) diff --git a/.github/setup-branch-protection.sh b/.github/setup-branch-protection.sh new file mode 100644 index 00000000..6450b9b7 --- /dev/null +++ b/.github/setup-branch-protection.sh @@ -0,0 +1,122 @@ +#!/usr/bin/env bash +# Establish `main` as the protected collaboration branch on the fork. +# +# Applies: +# 1) Repo-level security controls: Dependabot alerts, automated security +# fixes, secret scanning + push protection. +# 2) Branch protection on `main`: linear history, required PR review by a +# CODEOWNER, required status checks (CI + security), no force push, +# no deletion, resolved conversations. +# +# Idempotent — safe to re-run to reconcile state after any manual UI changes. +# +# Prereqs: +# - gh CLI authenticated as an admin on TX-RX/OpenTAKServer +# - `main` branch already exists on the fork +# - CI, CodeQL, and Security workflows have each run at least once on `main` +# (GitHub only lets you require a status check as a merge gate after it +# has been reported by a workflow run). +# +# Usage: +# bash .github/setup-branch-protection.sh +# REPO=TX-RX/OpenTAKServer BRANCH=main bash .github/setup-branch-protection.sh + +set -euo pipefail + +REPO="${REPO:-TX-RX/OpenTAKServer}" +BRANCH="${BRANCH:-main}" + +echo "== $REPO ==" +echo + +# ---------------------------------------------------------------------------- +# Repo-level security controls +# ---------------------------------------------------------------------------- + +echo "[1/5] Enabling Dependabot vulnerability alerts..." +gh api --method PUT -H "Accept: application/vnd.github+json" \ + "/repos/$REPO/vulnerability-alerts" >/dev/null +echo " ok" + +echo "[2/5] Enabling Dependabot automated security fixes..." +gh api --method PUT -H "Accept: application/vnd.github+json" \ + "/repos/$REPO/automated-security-fixes" >/dev/null +echo " ok" + +echo "[3/5] Enabling secret scanning + push protection..." +# Push protection blocks commits containing known secret patterns at git-push +# time, before the code lands on the remote. Requires the fork to be public +# (it is) or have GitHub Advanced Security (not needed for public repos). +gh api --method PATCH -H "Accept: application/vnd.github+json" \ + "/repos/$REPO" \ + -F 'security_and_analysis[secret_scanning][status]=enabled' \ + -F 'security_and_analysis[secret_scanning_push_protection][status]=enabled' \ + >/dev/null +echo " ok" + +# ---------------------------------------------------------------------------- +# Merge policy — squash-only. Every PR collapses into one clean commit on +# main, matching the linear-history rule in branch protection below. +# ---------------------------------------------------------------------------- + +echo "[4/5] Setting squash-only merge policy..." +gh api --method PATCH -H "Accept: application/vnd.github+json" \ + "/repos/$REPO" \ + -F allow_squash_merge=true \ + -F allow_merge_commit=false \ + -F allow_rebase_merge=false \ + -F squash_merge_commit_title=PR_TITLE \ + -F squash_merge_commit_message=PR_BODY \ + -F delete_branch_on_merge=true \ + >/dev/null +echo " ok" + +# ---------------------------------------------------------------------------- +# Branch protection on `main` +# ---------------------------------------------------------------------------- + +echo "[5/5] Applying branch protection to $REPO:$BRANCH..." + +# Required check names. These MUST match the workflow job "name:" (or the +# job-id if no name is set) as GitHub reports them. Update this list if +# job names change in ci.yml / codeql.yml / security.yml. +REQUIRED_CHECKS='[ + "lint", + "Build wheel", + "test (3.11)", + "test (3.12)", + "Analyze (python)", + "Bandit (Python SAST)", + "pip-audit (dependency CVEs)", + "gitleaks (secret scan)" +]' + +gh api \ + --method PUT \ + -H "Accept: application/vnd.github+json" \ + "/repos/$REPO/branches/$BRANCH/protection" \ + --input - <- + --health-cmd "pg_isready -U ots" + --health-interval 5s + --health-timeout 5s + --health-retries 10 + + rabbitmq: + image: rabbitmq:3-management + ports: ["5672:5672", "15672:15672"] + options: >- + --health-cmd "rabbitmq-diagnostics ping" + --health-interval 10s + --health-timeout 5s + --health-retries 10 + + env: + SQLALCHEMY_DATABASE_URI: postgresql+psycopg://ots:ots_test_password@127.0.0.1/ots + OTS_RABBITMQ_SERVER_ADDRESS: 127.0.0.1 + OTS_RABBITMQ_USERNAME: guest + OTS_RABBITMQ_PASSWORD: guest + + steps: + - uses: actions/checkout@v5 + with: + fetch-depth: 0 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v6 + with: + python-version: ${{ matrix.python-version }} + + - name: Install Poetry + uses: snok/install-poetry@v1 + with: + version: "2.2.1" + virtualenvs-create: true + virtualenvs-in-project: true + + - name: Cache virtualenv + uses: actions/cache@v4 + with: + path: .venv + key: venv-test-${{ runner.os }}-${{ matrix.python-version }}-${{ hashFiles('poetry.lock') }} + + - name: Install project + run: poetry install --with dev --no-interaction + + # Upstream test file is `tests/tests.py` which does not match pytest's + # default python_files pattern (test_*.py). Override so the file is + # discovered without modifying pyproject.toml. + # + # Upstream tests currently fail with a Flask-SQLAlchemy fixture error + # ("The current Flask app is not registered with this 'SQLAlchemy' + # instance"). Upstream has no CI running these tests so the breakage + # is invisible to them. Rather than fork tests/conftest.py to fix the + # fixture — which would guarantee a merge conflict on every upstream + # sync — this job runs tests informationally: it always exits 0 but + # emits a workflow warning if pytest fails, so PR reviewers see the + # test state without merges being blocked. + # + # The actual "build" gate that the required-check list depends on is + # the separate `build` job below (poetry build succeeds). + - name: pytest (informational) + run: | + poetry run pytest --override-ini="python_files=test_*.py tests.py" || { + code=$? + echo "::warning file=tests/conftest.py,title=pytest failed (informational)::pytest exited $code. Upstream fixtures need repair — treated as informational, not blocking merges. See FORK.md 'Test suite state' for detail." + exit 0 + } + + - name: Upload coverage artifact + if: always() + uses: actions/upload-artifact@v4 + with: + name: coverage-${{ matrix.python-version }} + path: | + coverage.xml + htmlcov/ + if-no-files-found: ignore + + build: + name: Build wheel + runs-on: ubuntu-latest + needs: lint + steps: + - uses: actions/checkout@v5 + with: + fetch-depth: 0 + + - name: Set up Python + uses: actions/setup-python@v6 + with: + python-version: "3.12" + + - name: Install Poetry + uses: snok/install-poetry@v1 + with: + version: "2.2.1" + + # poetry-dynamic-versioning is declared as a build-time dependency in + # pyproject.toml, but poetry build reads pyproject.toml before that + # dependency is available. Install the plugin into poetry itself. + - name: Install poetry-dynamic-versioning plugin + run: poetry self add "poetry-dynamic-versioning[plugin]" + + - name: Build sdist + wheel + run: poetry build + + - name: Verify artifacts + run: | + ls -la dist/ + test -n "$(ls dist/*.whl 2>/dev/null)" || { echo "No wheel produced"; exit 1; } + test -n "$(ls dist/*.tar.gz 2>/dev/null)" || { echo "No sdist produced"; exit 1; } + + - name: Upload build artifacts + uses: actions/upload-artifact@v4 + with: + name: ci-build-artifacts + path: dist/ + retention-days: 7 diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 00000000..48c44887 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,42 @@ +name: CodeQL + +on: + push: + branches: [main, master] + pull_request: + branches: [main] + schedule: + # Weekly re-scan against latest CodeQL rules — catches new CVE patterns + # in code that hasn't changed. + - cron: "23 5 * * 1" + +concurrency: + group: codeql-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + analyze: + name: Analyze (${{ matrix.language }}) + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + strategy: + fail-fast: false + matrix: + language: [python] + + steps: + - uses: actions/checkout@v5 + + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: ${{ matrix.language }} + queries: security-extended,security-and-quality + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v3 + with: + category: "/language:${{ matrix.language }}" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..3d87daa7 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,70 @@ +name: Release + +on: + push: + tags: + - "[0-9]+.[0-9]+.[0-9]+.[0-9]+" + workflow_dispatch: + inputs: + tag: + description: "Existing tag to release (e.g. 1.7.11.1)" + required: true + +permissions: + contents: write + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v5 + with: + fetch-depth: 0 + ref: ${{ inputs.tag || github.ref }} + + - name: Set up Python + uses: actions/setup-python@v6 + with: + python-version: "3.12" + + - name: Install Poetry + uses: snok/install-poetry@v1 + with: + version: "2.2.1" + + - name: Verify version derives from tag + run: | + poetry self add "poetry-dynamic-versioning[plugin]" + RESOLVED="$(poetry version --short)" + TAG="${{ inputs.tag || github.ref_name }}" + echo "resolved=$RESOLVED tag=$TAG" + if [ "$RESOLVED" != "$TAG" ]; then + echo "::error::poetry version ($RESOLVED) does not match tag ($TAG)" + exit 1 + fi + + - name: Build sdist + wheel + run: poetry build + + - name: Upload build artifacts + uses: actions/upload-artifact@v4 + with: + name: dist + path: dist/ + + release: + runs-on: ubuntu-latest + needs: build + steps: + - uses: actions/download-artifact@v5 + with: + name: dist + path: dist/ + + - name: Create GitHub Release + uses: softprops/action-gh-release@v2 + with: + tag_name: ${{ inputs.tag || github.ref_name }} + name: ${{ inputs.tag || github.ref_name }} + generate_release_notes: true + files: dist/* diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml new file mode 100644 index 00000000..6ec6bb86 --- /dev/null +++ b/.github/workflows/security.yml @@ -0,0 +1,147 @@ +name: Security + +on: + push: + branches: [main, master] + pull_request: + branches: [main] + schedule: + # Weekly re-scan catches new CVE disclosures against unchanged deps. + - cron: "37 5 * * 1" + workflow_dispatch: + +concurrency: + group: security-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + bandit: + name: Bandit (Python SAST) + runs-on: ubuntu-latest + permissions: + contents: read + security-events: write + steps: + - uses: actions/checkout@v5 + + - name: Set up Python + uses: actions/setup-python@v6 + with: + python-version: "3.12" + + - name: Install Bandit + run: pip install "bandit[sarif,toml]==1.8.0" + + # Full scan → SARIF for the Security tab, informational only. + - name: Bandit scan (SARIF upload) + run: | + bandit -r opentakserver \ + -f sarif -o bandit.sarif \ + --exit-zero + + - name: Upload Bandit SARIF + if: always() + uses: github/codeql-action/upload-sarif@v3 + with: + sarif_file: bandit.sarif + category: bandit + + # Gating scan compares against .bandit-baseline.json — pre-existing + # HIGH findings in upstream code are accepted; any NEW HIGH finding + # blocks the merge. Regenerate the baseline only when the operator + # has intentionally reviewed and accepted new findings: + # bandit -r opentakserver -f json -o .bandit-baseline.json \ + # --severity-level high + - name: Bandit gate (baseline-diff on HIGH severity) + run: | + bandit -r opentakserver \ + --baseline .bandit-baseline.json \ + --severity-level high + + pip-audit: + name: pip-audit (dependency CVEs) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v5 + with: + fetch-depth: 0 + + - name: Set up Python + uses: actions/setup-python@v6 + with: + python-version: "3.12" + + - name: Install Poetry + uses: snok/install-poetry@v1 + with: + version: "2.2.1" + + - name: Export requirements from poetry.lock + run: | + poetry self add poetry-plugin-export + poetry export --without-hashes --format requirements.txt --output requirements.txt + + - name: Install pip-audit + run: pip install "pip-audit==2.7.3" + + # Smart gating: + # - On a PR that changes poetry.lock (i.e. actually touches the + # dep tree), pip-audit runs STRICTLY. Any CVE not in + # .pip-audit-ignore.txt fails the merge. This is the real + # guard against introducing vulnerable deps. + # - On any other trigger (PRs that don't touch deps, pushes, + # scheduled runs), pip-audit runs INFORMATIONALLY. Findings + # are visible in the log but do not fail the job — background + # CVE disclosures against unchanged pinned versions would + # otherwise force every unrelated PR to bump the ignore list. + # Dependabot (enabled by setup-branch-protection.sh) opens PRs + # to actually fix those; the weekly cron run keeps the CVE + # report fresh. + - name: Detect poetry.lock changes + id: lockchange + run: | + if [ "${{ github.event_name }}" = "pull_request" ]; then + if git diff --name-only "origin/${{ github.base_ref }}...HEAD" | grep -qx 'poetry.lock'; then + echo "changed=true" >> $GITHUB_OUTPUT + echo "poetry.lock changed in this PR — pip-audit will run in strict mode" + else + echo "changed=false" >> $GITHUB_OUTPUT + echo "poetry.lock unchanged — pip-audit will run informationally" + fi + else + echo "changed=false" >> $GITHUB_OUTPUT + echo "Non-PR trigger — pip-audit will run informationally" + fi + + - name: Run pip-audit + run: | + IGNORE_FLAGS=() + while IFS= read -r line; do + id="${line%%#*}" + id="$(echo -n "$id" | tr -d '[:space:]')" + [ -n "$id" ] && IGNORE_FLAGS+=(--ignore-vuln "$id") + done < .pip-audit-ignore.txt + echo "Ignoring $((${#IGNORE_FLAGS[@]} / 2)) CVE IDs from .pip-audit-ignore.txt" + if [ "${{ steps.lockchange.outputs.changed }}" = "true" ]; then + pip-audit --requirement requirements.txt --strict "${IGNORE_FLAGS[@]}" + else + pip-audit --requirement requirements.txt "${IGNORE_FLAGS[@]}" || { + echo "::warning::pip-audit found vulnerabilities in unchanged deps — informational only. Dependabot will open PRs to fix; regenerate baseline as those land." + exit 0 + } + fi + + gitleaks: + name: gitleaks (secret scan) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v5 + with: + # Full history so gitleaks can inspect the whole PR range. + fetch-depth: 0 + + - name: Run gitleaks + uses: gitleaks/gitleaks-action@v2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITLEAKS_ENABLE_UPLOAD_ARTIFACT: true diff --git a/.pip-audit-ignore.txt b/.pip-audit-ignore.txt new file mode 100644 index 00000000..91203a5d --- /dev/null +++ b/.pip-audit-ignore.txt @@ -0,0 +1,133 @@ +# pip-audit vulnerability baseline +# +# Each line is one CVE ID to ignore (comments and blank lines skipped). +# The security workflow reads this file and passes each ID as +# --ignore-vuln to pip-audit. Any CVE NOT listed here that pip-audit +# discovers against the current poetry.lock will block the PR. +# +# These are all pre-existing against upstream's pinned dependency +# versions. Dependabot (enabled by setup-branch-protection.sh) opens +# PRs to bump these. When a PR upgrades a dep past the vulnerable +# version, remove the associated CVE IDs from this file so the gate +# stays real. +# +# Baseline captured 2026-07-07 from upstream master @ commit 122064d. + +# aiohttp 3.13.3 +GHSA-4fvr-rgm6-gqmc +GHSA-2fqr-mr3j-6wp8 +GHSA-63hw-fmq6-xxg2 +GHSA-m6qw-4cw2-hm4m +GHSA-hpj7-wq8m-9hgp +GHSA-g3cq-j2xw-wf74 +GHSA-9x8q-7h8h-wcw9 +GHSA-xcgm-r5h9-7989 +# aiohttp 3.13.3 (additional CVEs disclosed 2026-07-07) +PYSEC-2026-237 +GHSA-p998-jp59-783m +GHSA-hcc4-c3v8-rx92 +GHSA-m5qp-6w8w-w647 +GHSA-3wq7-rqq7-wx6j +GHSA-mwh4-6h8g-pg8w +GHSA-966j-vmvw-g2g9 +GHSA-63hf-3vf5-4wqf +GHSA-c427-h43c-vf67 +GHSA-w2fm-2cpv-w7v5 +GHSA-2vrm-gr82-f7m5 +GHSA-jg22-mg44-37j8 +GHSA-hg6j-4rv6-33pg + +# bleach 6.3.0 +GHSA-g75f-g53v-794x +GHSA-gj48-438w-jh9v +GHSA-8rfp-98v4-mmr6 + +# msgpack 1.1.2 +GHSA-6v7p-g79w-8964 + +# cbor2 5.8.0 +GHSA-3c37-wwvx-h642 + +# cryptography 46.0.4 +PYSEC-2026-36 +PYSEC-2026-35 +GHSA-r6ph-v2qm-q3c2 +GHSA-537c-gmf6-5ccf + +# dulwich 0.24.1 (pinned upstream — cannot bump) +GHSA-897w-fcg9-f6xj +GHSA-9277-mp7x-85jf +GHSA-555p-6grf-mh7f +GHSA-xrvj-v92f-53gj +GHSA-gfhv-vqv2-4544 + +# flask 3.1.2 +GHSA-68rp-wp8r-4726 + +# idna 3.11 +PYSEC-2026-215 + +# lxml 6.0.2 +PYSEC-2026-87 + +# mako 1.3.10 +GHSA-2h4p-vjrc-8xpq + +# requests 2.32.5 +GHSA-gc5v-m9x4-r6x2 + +# urllib3 2.6.3 +PYSEC-2026-142 +PYSEC-2026-141 + +# pillow 12.1.0 +PYSEC-2026-165 +GHSA-cfh3-3jmp-rvhc +GHSA-whj4-6x5x-4v2j +GHSA-5xmw-vc9v-4wf2 +GHSA-r73j-pqj5-w3x7 +GHSA-pwv6-vv43-88gr + +# poetry 2.2.1 +GHSA-2599-h6xx-hpxp +GHSA-73h3-mf4w-8647 + +# protobuf 6.33.1 +GHSA-7gcm-g887-7qv7 + +# pyasn1 0.6.2 +GHSA-jr27-m4p2-rc6r + +# pygments 2.19.2 +GHSA-5239-wwwm-4pmq + +# pyjwt 2.10.0 +PYSEC-2026-120 +PYSEC-2025-183 +PYSEC-2026-179 +PYSEC-2026-175 +PYSEC-2026-177 +PYSEC-2026-178 +PYSEC-2026-176 +GHSA-75c5-xw7c-p5pm + +# pyopenssl 25.3.0 +GHSA-vp96-hxj8-p424 +GHSA-5pwr-322w-8jr4 + +# python-engineio 4.13.0 +GHSA-cgwc-pv48-fhj5 +GHSA-m9gh-vj53-gvh9 + +# python-socketio 5.14.3 +GHSA-5w7q-77mv-v69f + +# werkzeug 3.1.5 +GHSA-29vq-49wr-vm6x + +# yt-dlp 2026.1.29 +GHSA-g3gw-q23r-pgqm +GHSA-f7j3-774f-rfhj +GHSA-c6mh-fpjc-4pr3 +GHSA-vx4q-3cr2-7cg2 +GHSA-69qj-pvh9-c5wg diff --git a/FORK.md b/FORK.md new file mode 100644 index 00000000..456ed0a5 --- /dev/null +++ b/FORK.md @@ -0,0 +1,112 @@ +# TX-RX/OpenTAKServer — fork notes + +This is a downstream fork of [`brian7704/OpenTAKServer`](https://github.com/brian7704/OpenTAKServer) +maintained by TX-RX. It carries a small set of patches that either haven't landed upstream yet or +that upstream has declined to merge. Everything else tracks upstream. + +## Branch layout + +| Branch | Purpose | +| ------- | ------------------------------------------------------------------------------------------- | +| `master` | Pristine mirror of upstream `brian7704/OpenTAKServer:master`. Never modified directly. | +| `main` | Default branch. `master` + downstream patches. All releases cut from here. | +| `feature/*`, `fix/*` | Work branches. PR into `main`. Where possible, also submitted upstream. | + +## Syncing `master` from upstream + +`master` should always fast-forward from upstream. If it ever needs a force update, something has +gone wrong — investigate before proceeding. + +```bash +git fetch origin +git checkout master +git merge --ff-only origin/master +git push fork master +``` + +## Rebasing `main` on the new upstream + +```bash +git checkout main +git fetch fork +git rebase master # replay downstream patches onto the new upstream +# resolve any conflicts, then: +git push --force-with-lease fork main +``` + +Conflicts here are the load-bearing signal that a downstream patch has been overtaken by upstream — +drop the patch if so. + +## Current downstream patches + +Kept intentionally short. When a patch is submitted upstream, link the PR; when it lands upstream, +delete the row and the patch drops out of `main` on the next rebase. + +| Patch | Reason downstream | Upstream status | +| ------------------------------------ | ----------------------------------------------------- | --------------- | +| `fix/qr-token-security` | Enforce single-use enrollment QR by default | Declined (PR #311) — upstream considers unlimited-use intentional | + +## Security gating + +Every PR into `main` must pass: + +- **CI** — black/isort/flake8, wheel build, pytest (`.github/workflows/ci.yml`) +- **CodeQL** — Python SAST via GitHub's security-extended query pack (`.github/workflows/codeql.yml`) +- **Bandit** — Python SAST, HIGH severity, baseline-diff against `.bandit-baseline.json` (`.github/workflows/security.yml`) +- **pip-audit** — dependency CVE scan against `poetry.lock`. On PRs that change `poetry.lock`, runs strictly against `.pip-audit-ignore.txt`. On PRs that don't touch deps, runs informationally so unrelated changes don't get blocked by background CVE churn against unchanged pinned versions (`.github/workflows/security.yml`) +- **gitleaks** — secret pattern scan across the PR range (`.github/workflows/security.yml`) + +### Test suite state + +Upstream's `tests/tests.py` currently fails against upstream `master` with a Flask-SQLAlchemy +fixture error (`"The current Flask app is not registered with this 'SQLAlchemy' instance"`). +Upstream has no CI running these tests so the breakage is invisible to them. The CI job runs +tests informationally — it emits a workflow warning if pytest fails but does not block merges. +The `Build wheel` job (`poetry build`) is the actual required build gate. + +Fixing the fixture would require modifying `tests/conftest.py`, guaranteeing a merge conflict on +every upstream sync. Owed follow-up: propose a conftest fix upstream so the divergence resolves. + +### Baseline files + +Bandit and pip-audit both run in baseline-diff mode. Pre-existing findings against upstream code +and pinned dependencies are recorded as accepted; any NEW finding blocks merge. + +- **`.bandit-baseline.json`** — snapshot of current HIGH-severity Bandit findings. Regenerate only + when the operator has intentionally accepted a new HIGH finding: + ```bash + poetry run bandit -r opentakserver -f json -o .bandit-baseline.json --severity-level high + ``` +- **`.pip-audit-ignore.txt`** — one CVE ID per line (comments with `#` allowed). When a Dependabot + PR upgrades a dep past the vulnerable range, drop the corresponding CVE IDs from this file so + the gate stays real. + +Repo-level controls layered on top: + +- **Secret scanning + push protection** — GitHub blocks the push itself if a + known secret pattern is detected, before the code lands on the remote. +- **Dependabot vulnerability alerts** — surfaces new CVEs against pinned deps. +- **Dependabot automated security fixes** — opens PRs to upgrade vulnerable deps. +- **Squash-only merge policy** — every PR collapses to a single commit on + `main`. Preserves linear history (required by branch protection) and keeps + the downstream patch inventory in `FORK.md` easy to line up against + actual commits. Merge commits and rebase merges are disabled at the repo + level. Merged PR branches are auto-deleted. + +All the above are configured by `.github/setup-branch-protection.sh`. Run it after any change +to the required-check names. + +## Deploy verification + +Per project convention, non-trivial patches are verified on the Azure OTS install before merging to +`main`: + +1. Push the feature branch to `fork`. +2. CI builds a wheel artifact. +3. Deploy the wheel to Azure. +4. Verify the change in the browser / with the affected client. +5. Squash-merge to `main`. + +## Releases + +See [`RELEASE.md`](./RELEASE.md). diff --git a/RELEASE.md b/RELEASE.md new file mode 100644 index 00000000..e9431728 --- /dev/null +++ b/RELEASE.md @@ -0,0 +1,57 @@ +# Release process + +## Versioning + +Version numbers are derived from git tags by +[`poetry-dynamic-versioning`](https://github.com/mtkennerly/poetry-dynamic-versioning). The regex in +`pyproject.toml` (`(?P\d+(\.\d+)*)`) only accepts numeric segments, so we can't use PEP 440 +local versions like `1.7.11+txrx.1` without modifying `pyproject.toml` — which would conflict with +every upstream sync. + +**Scheme:** 4-part semver, where the 4th segment is the downstream patch counter. + +- `1.7.11` — upstream release (their tag, unmodified) +- `1.7.11.1` — first TX-RX downstream release on top of upstream `1.7.11` +- `1.7.11.2` — second downstream release on top of the same upstream base +- `1.7.12` (upstream) → reset counter → `1.7.12.1` for the next downstream release + +Bump the 4th segment for any release from this fork, even docs/CI-only releases, so downstream +consumers can pin exactly. + +## Cutting a release + +1. Confirm `main` is green on CI and the desired commit is on `main`. +2. Confirm the deploy has been verified on Azure OTS (per `FORK.md`). +3. Tag and push: + ```bash + git checkout main + git pull fork main + git tag 1.7.11.1 # no `v` prefix — poetry-dynamic-versioning matches numeric tags + git push fork 1.7.11.1 + ``` +4. `release.yml` fires on the tag: builds sdist/wheel, uploads them to a GitHub Release with + auto-generated notes. +5. `docker.yml` fires on the GitHub Release publish and pushes container images to `ghcr.io`. + + Note: the upstream `docker.yml` matrix pushes to `ghcr.io/brian7704/*` — hard-coded, not derived + from `github.repository`. If you want fork images at `ghcr.io/tx-rx/*`, patch that matrix on + `main`. Left alone for now to keep the docker workflow in sync with upstream. + +## If the release fails + +- Wheel build mismatched the tag: `release.yml` fails fast with the resolved version. Delete the + tag on the fork remote, fix the underlying issue, re-tag. + ```bash + git push fork :refs/tags/1.7.11.1 + git tag -d 1.7.11.1 + ``` +- Docker publish failed but wheel is out: re-run `docker.yml` via workflow_dispatch. The GitHub + Release itself is fine. + +## Do not + +- **Do not** move an existing tag. Cut a new one instead. +- **Do not** publish to PyPI. This is a fork; PyPI would collide with upstream's `OpenTAKServer` + package name. +- **Do not** tag from `master` — that would attach a downstream version to a pristine upstream + commit and confuse anyone who diffs. diff --git a/opentakserver/blueprints/marti_api/cot_marti_api.py b/opentakserver/blueprints/marti_api/cot_marti_api.py index c4a6f379..801606b6 100644 --- a/opentakserver/blueprints/marti_api/cot_marti_api.py +++ b/opentakserver/blueprints/marti_api/cot_marti_api.py @@ -48,7 +48,10 @@ def get_all_cot(uid): query = db.session.query(CoT).filter_by(uid=uid) if sec_ago: try: - query = query.filter(CoT.start >= datetime.datetime.now(datetime.UTC) - datetime.timedelta(seconds=int(sec_ago))) + query = query.filter( + CoT.start + >= datetime.datetime.now(datetime.UTC) - datetime.timedelta(seconds=int(sec_ago)) + ) except ValueError: return ( jsonify( diff --git a/opentakserver/blueprints/ots_api/casevac_api.py b/opentakserver/blueprints/ots_api/casevac_api.py index 10064aa6..5b01bc39 100644 --- a/opentakserver/blueprints/ots_api/casevac_api.py +++ b/opentakserver/blueprints/ots_api/casevac_api.py @@ -6,7 +6,6 @@ from flask import Blueprint, jsonify, request from flask_babel import gettext from flask_security import auth_required, current_user -from opentakserver.models.GroupUser import GroupUser from sqlalchemy import insert, update from werkzeug.datastructures import ImmutableMultiDict @@ -19,6 +18,7 @@ from opentakserver.models.CoT import CoT from opentakserver.models.EUD import EUD from opentakserver.models.Group import Group +from opentakserver.models.GroupUser import GroupUser from opentakserver.models.Point import Point from opentakserver.models.ZMIST import ZMIST diff --git a/opentakserver/cot_parser/cot_parser.py b/opentakserver/cot_parser/cot_parser.py index 31ce5158..835dca80 100644 --- a/opentakserver/cot_parser/cot_parser.py +++ b/opentakserver/cot_parser/cot_parser.py @@ -1,6 +1,5 @@ import base64 import datetime -from datetime import timedelta, timezone import logging import os import platform @@ -9,6 +8,7 @@ import time import traceback import uuid +from datetime import timedelta, timezone from logging.handlers import TimedRotatingFileHandler import bleach @@ -24,7 +24,6 @@ from flask_security.models import fsqla from flask_socketio import SocketIO from meshtastic import BROADCAST_NUM, mesh_pb2, mqtt_pb2, portnums_pb2 -from opentakserver.models.GroupUser import GroupUser from pika.channel import Channel from sqlalchemy import exc, insert, select, update @@ -45,6 +44,7 @@ from opentakserver.models.GeoChat import GeoChat from opentakserver.models.Group import Group from opentakserver.models.GroupMission import GroupMission +from opentakserver.models.GroupUser import GroupUser from opentakserver.models.Icon import Icon from opentakserver.models.Marker import Marker from opentakserver.models.Meshtastic import MeshtasticChannel diff --git a/opentakserver/eud_handler/EudHandler.py b/opentakserver/eud_handler/EudHandler.py index ddd51e5d..bb382ebf 100644 --- a/opentakserver/eud_handler/EudHandler.py +++ b/opentakserver/eud_handler/EudHandler.py @@ -11,9 +11,9 @@ import traceback import uuid from logging.handlers import TimedRotatingFileHandler -from socket import socket, SHUT_RDWR +from socket import SHUT_RDWR, socket from threading import Thread -from xml.etree.ElementTree import Element, SubElement, tostring, fromstring, ParseError +from xml.etree.ElementTree import Element, ParseError, SubElement, fromstring, tostring import bleach import colorlog @@ -24,16 +24,16 @@ from bs4 import BeautifulSoup from flask import Flask from flask_ldap3_login import AuthenticationResponseStatus -from flask_security import SQLAlchemyUserDatastore, Security, verify_password +from flask_security import Security, SQLAlchemyUserDatastore, verify_password from flask_security.models import fsqla from pika.channel import Channel -from sqlalchemy import insert, update, select +from sqlalchemy import insert, select, update -from opentakserver.EmailValidator import EmailValidator -from opentakserver.PasswordValidator import PasswordValidator from opentakserver.defaultconfig import DefaultConfig -from opentakserver.extensions import logger as ots_logger, db, ldap_manager -from opentakserver.functions import iso8601_string_from_datetime, datetime_from_iso8601_string +from opentakserver.EmailValidator import EmailValidator +from opentakserver.extensions import db, ldap_manager +from opentakserver.extensions import logger as ots_logger +from opentakserver.functions import datetime_from_iso8601_string, iso8601_string_from_datetime # These unused imports are required by SQLAlchemy, don't remove them from opentakserver.models.Alert import Alert @@ -63,6 +63,7 @@ from opentakserver.models.VideoStream import VideoStream from opentakserver.models.WebAuthn import WebAuthn from opentakserver.models.ZMIST import ZMIST +from opentakserver.PasswordValidator import PasswordValidator class EudHandler(socketserver.BaseRequestHandler): diff --git a/opentakserver/eud_handler/eud_handler.py b/opentakserver/eud_handler/eud_handler.py index 314c721b..1e7b6bb6 100644 --- a/opentakserver/eud_handler/eud_handler.py +++ b/opentakserver/eud_handler/eud_handler.py @@ -11,18 +11,18 @@ from apscheduler.jobstores import sqlalchemy from flask import Flask, jsonify from flask_babel import gettext -from flask_security import SQLAlchemyUserDatastore, Security +from flask_security import Security, SQLAlchemyUserDatastore from flask_security.models import fsqla -from opentakserver.EmailValidator import EmailValidator -from opentakserver.PasswordValidator import PasswordValidator from opentakserver.defaultconfig import DefaultConfig +from opentakserver.EmailValidator import EmailValidator from opentakserver.eud_handler import EudHandler from opentakserver.eud_handler.EudHandlerSSL import EudHandlerSSL from opentakserver.eud_handler.EudServer import EudServer from opentakserver.eud_handler.EudServerSSL import EudServerSSL from opentakserver.eud_handler.EudServerUdp import EudServerUdp -from opentakserver.extensions import logger, db, ldap_manager +from opentakserver.extensions import db, ldap_manager, logger +from opentakserver.PasswordValidator import PasswordValidator def args(): diff --git a/opentakserver/migrations/versions/00442761c803_added_mission_guid_to_missionrole_and_.py b/opentakserver/migrations/versions/00442761c803_added_mission_guid_to_missionrole_and_.py index b50e80c8..2a62c385 100644 --- a/opentakserver/migrations/versions/00442761c803_added_mission_guid_to_missionrole_and_.py +++ b/opentakserver/migrations/versions/00442761c803_added_mission_guid_to_missionrole_and_.py @@ -5,40 +5,41 @@ Create Date: 2026-03-28 19:06:27.954358 """ -from alembic import op + import sqlalchemy as sa +from alembic import op from sqlalchemy.dialects import mysql # revision identifiers, used by Alembic. -revision = '00442761c803' -down_revision = '6a7929c07690' +revision = "00442761c803" +down_revision = "6a7929c07690" branch_labels = None depends_on = None def upgrade(): # ### commands auto generated by Alembic - please adjust! ### - with op.batch_alter_table('mission_invitations', schema=None) as batch_op: - batch_op.add_column(sa.Column('mission_guid', sa.String(length=255), nullable=True)) + with op.batch_alter_table("mission_invitations", schema=None) as batch_op: + batch_op.add_column(sa.Column("mission_guid", sa.String(length=255), nullable=True)) - with op.batch_alter_table('mission_roles', schema=None) as batch_op: - batch_op.add_column(sa.Column('mission_guid', sa.String(length=255), nullable=True)) - batch_op.alter_column('mission_name', - existing_type=mysql.VARCHAR(length=255), - nullable=True) + with op.batch_alter_table("mission_roles", schema=None) as batch_op: + batch_op.add_column(sa.Column("mission_guid", sa.String(length=255), nullable=True)) + batch_op.alter_column( + "mission_name", existing_type=mysql.VARCHAR(length=255), nullable=True + ) # ### end Alembic commands ### def downgrade(): # ### commands auto generated by Alembic - please adjust! ### - with op.batch_alter_table('mission_roles', schema=None) as batch_op: - batch_op.alter_column('mission_name', - existing_type=mysql.VARCHAR(length=255), - nullable=False) - batch_op.drop_column('mission_guid') - - with op.batch_alter_table('mission_invitations', schema=None) as batch_op: - batch_op.drop_column('mission_guid') + with op.batch_alter_table("mission_roles", schema=None) as batch_op: + batch_op.alter_column( + "mission_name", existing_type=mysql.VARCHAR(length=255), nullable=False + ) + batch_op.drop_column("mission_guid") + + with op.batch_alter_table("mission_invitations", schema=None) as batch_op: + batch_op.drop_column("mission_guid") # ### end Alembic commands ### diff --git a/opentakserver/migrations/versions/6a7929c07690_altered_foreign_key_on_device_profiles.py b/opentakserver/migrations/versions/6a7929c07690_altered_foreign_key_on_device_profiles.py index 512f00c3..579c91a2 100644 --- a/opentakserver/migrations/versions/6a7929c07690_altered_foreign_key_on_device_profiles.py +++ b/opentakserver/migrations/versions/6a7929c07690_altered_foreign_key_on_device_profiles.py @@ -6,8 +6,8 @@ """ -from alembic import op import sqlalchemy as sa +from alembic import op # revision identifiers, used by Alembic. revision = "6a7929c07690" diff --git a/opentakserver/models/DeviceProfiles.py b/opentakserver/models/DeviceProfiles.py index fca5f46c..14c557f7 100644 --- a/opentakserver/models/DeviceProfiles.py +++ b/opentakserver/models/DeviceProfiles.py @@ -25,10 +25,7 @@ class DeviceProfiles(db.Model): active: Mapped[bool] = mapped_column(Boolean, default=True) publish_time: Mapped[datetime] = mapped_column(DateTime) eud_uid: Mapped[str] = mapped_column( - String(255), - ForeignKey("euds.uid", ondelete="CASCADE"), - nullable=True, - default=None + String(255), ForeignKey("euds.uid", ondelete="CASCADE"), nullable=True, default=None ) eud = relationship("EUD", back_populates="profiles") diff --git a/opentakserver/models/MissionChange.py b/opentakserver/models/MissionChange.py index 625af79c..d92dba05 100644 --- a/opentakserver/models/MissionChange.py +++ b/opentakserver/models/MissionChange.py @@ -114,7 +114,9 @@ def generate_mission_change_cot( ) if not mission: - mission = db.session.execute(db.session.query(Mission).filter_by(name=mission_name)).scalar() + mission = db.session.execute( + db.session.query(Mission).filter_by(name=mission_name) + ).scalar() detail = SubElement(event, "detail") mission_element = SubElement( diff --git a/opentakserver/models/MissionInvitation.py b/opentakserver/models/MissionInvitation.py index 181b1168..fff4fd2c 100644 --- a/opentakserver/models/MissionInvitation.py +++ b/opentakserver/models/MissionInvitation.py @@ -23,7 +23,9 @@ class MissionInvitation(db.Model): __tablename__ = "mission_invitations" id: Mapped[int] = mapped_column(Integer, primary_key=True) - mission_name: Mapped[str] = mapped_column(String(255), ForeignKey("missions.name"), nullable=True) + mission_name: Mapped[str] = mapped_column( + String(255), ForeignKey("missions.name"), nullable=True + ) mission_guid: Mapped[str] = mapped_column(String(255), nullable=True) client_uid: Mapped[str] = mapped_column( String(255), ForeignKey("euds.uid", ondelete="CASCADE"), nullable=True diff --git a/opentakserver/models/MissionRole.py b/opentakserver/models/MissionRole.py index 348e2054..762569df 100644 --- a/opentakserver/models/MissionRole.py +++ b/opentakserver/models/MissionRole.py @@ -46,7 +46,9 @@ class MissionRole(db.Model): username: Mapped[str] = mapped_column(String(255)) createTime: Mapped[datetime] = mapped_column(DateTime) role_type: Mapped[str] = mapped_column(String(255)) - mission_name: Mapped[str] = mapped_column(String(255), ForeignKey("missions.name"), nullable=True) + mission_name: Mapped[str] = mapped_column( + String(255), ForeignKey("missions.name"), nullable=True + ) mission_guid: Mapped[str] = mapped_column(String(255), nullable=True) mission = relationship("Mission", back_populates="roles", uselist=False)