forward-netbox 3.0.2__tar.gz → 3.0.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (593) hide show
  1. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/PKG-INFO +7 -4
  2. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/README.md +5 -3
  3. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/__init__.py +1 -1
  4. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/management/commands/forward_seed_ui_harness.py +2 -2
  5. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/forward_devices.nqe +12 -3
  6. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/forward_devices_with_netbox_aliases.nqe +12 -3
  7. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/templates/forward_netbox/forwardsync_scope_reconciliation.html +5 -1
  8. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_apply_engine.py +60 -0
  9. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_bulk_merge.py +14 -3
  10. forward_netbox-3.0.4/forward_netbox/tests/test_bundle_triage_diagnostics.py +208 -0
  11. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_endpoints_import.py +26 -0
  12. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_merge_rule_rejection.py +12 -0
  13. forward_netbox-3.0.4/forward_netbox/tests/test_null_vrf_identity.py +119 -0
  14. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_optional_plugin_versions.py +3 -3
  15. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_ospf_drift_comparison.py +23 -1
  16. forward_netbox-3.0.4/forward_netbox/tests/test_ospf_instance_names.py +188 -0
  17. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_plugin_integrations.py +14 -4
  18. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_primary_ip.py +55 -0
  19. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_primary_ip_integration.py +43 -0
  20. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_runtime_dependency_check.py +1 -1
  21. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_scope_reconciliation_site_aware.py +56 -4
  22. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_site_relabel_pairs_merge.py +34 -0
  23. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_site_relabel_prompts.py +20 -0
  24. forward_netbox-3.0.4/forward_netbox/tests/test_stale_untagged_vlan_cleared.py +141 -0
  25. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_sync.py +12 -12
  26. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/apply_engine_bulk.py +99 -16
  27. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/bundle_diagnostics.py +29 -0
  28. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/diagnostics.py +8 -0
  29. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/fast_baseline.py +1 -1
  30. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/plugin_integrations/registry.py +28 -3
  31. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/primary_ip.py +110 -6
  32. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/scope_reconciliation.py +60 -19
  33. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/sync_contracts.py +8 -4
  34. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/sync_interface.py +33 -0
  35. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/sync_routing_impl.py +90 -17
  36. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/validated_runtime.py +1 -1
  37. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/views.py +236 -1
  38. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/pyproject.toml +8 -2
  39. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/LICENSE +0 -0
  40. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/api/__init__.py +0 -0
  41. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/api/serializers.py +0 -0
  42. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/api/urls.py +0 -0
  43. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/api/views.py +0 -0
  44. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/change_control/__init__.py +0 -0
  45. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/change_control/choices.py +0 -0
  46. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/change_control/criteria.py +0 -0
  47. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/change_control/evidence.py +0 -0
  48. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/change_control/gates.py +0 -0
  49. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/change_control/policy.py +0 -0
  50. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/change_control/predict.py +0 -0
  51. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/change_control/state_machine.py +0 -0
  52. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/choices.py +0 -0
  53. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/exceptions.py +0 -0
  54. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/filtersets.py +0 -0
  55. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/forms.py +0 -0
  56. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/jobs.py +0 -0
  57. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/management/__init__.py +0 -0
  58. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/management/commands/__init__.py +0 -0
  59. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/management/commands/forward_accept_merge_failures.py +0 -0
  60. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/management/commands/forward_apic_cimc_readiness_audit.py +0 -0
  61. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/management/commands/forward_apply_identity_audit.py +0 -0
  62. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/management/commands/forward_blocker_audit.py +0 -0
  63. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/management/commands/forward_changediff_audit.py +0 -0
  64. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/management/commands/forward_collection_gap_alert.py +0 -0
  65. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/management/commands/forward_device_name_ambiguity_audit.py +0 -0
  66. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/management/commands/forward_device_scope_reconciliation_audit.py +0 -0
  67. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/management/commands/forward_dlm_hardware_notice_audit.py +0 -0
  68. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/management/commands/forward_fast_baseline_preflight.py +0 -0
  69. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/management/commands/forward_interface_vlan_audit.py +0 -0
  70. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/management/commands/forward_link_vsys_parents.py +0 -0
  71. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/management/commands/forward_metrics.py +0 -0
  72. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/management/commands/forward_module_readiness.py +0 -0
  73. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/management/commands/forward_ownership_audit.py +0 -0
  74. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/management/commands/forward_primary_ip_audit.py +0 -0
  75. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/management/commands/forward_profile_merge.py +0 -0
  76. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/management/commands/forward_pushdown_profile.py +0 -0
  77. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/management/commands/forward_query_diff_coverage_audit.py +0 -0
  78. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/management/commands/forward_resolve_query_ids.py +0 -0
  79. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/management/commands/forward_routing_dangling_audit.py +0 -0
  80. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/management/commands/forward_scope_ipam_audit.py +0 -0
  81. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/management/commands/forward_smoke_sync.py +0 -0
  82. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/management/commands/forward_stuck_job_alert.py +0 -0
  83. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/management/commands/forward_stuck_job_recover.py +0 -0
  84. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/management/commands/forward_tag_delete_eligible.py +0 -0
  85. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/management/commands/forward_validation_org_query_audit.py +0 -0
  86. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/management/commands/forward_warning_audit.py +0 -0
  87. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/management/commands/forward_watch_sync.py +0 -0
  88. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/migrations/0001_initial.py +0 -0
  89. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/migrations/0002_add_coalesce_fields.py +0 -0
  90. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/migrations/0003_forwardingestionissue_context_fields.py +0 -0
  91. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/migrations/0004_forwardingestion_baseline_fields.py +0 -0
  92. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/migrations/0005_validation_and_reporting.py +0 -0
  93. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/migrations/0006_alter_forwardnqemap_netbox_model.py +0 -0
  94. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/migrations/0007_forwardingestion_persisted_change_counters.py +0 -0
  95. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/migrations/0008_alter_forwardnqemap_netbox_model.py +0 -0
  96. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/migrations/0009_alter_forwardnqemap_netbox_model.py +0 -0
  97. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/migrations/0010_forwardvalidationrun_override_applied_and_more.py +0 -0
  98. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/migrations/0011_forwardingestion_change_request_id.py +0 -0
  99. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/migrations/0012_forwardnqemap_query_reference.py +0 -0
  100. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/migrations/0013_execution_run_step.py +0 -0
  101. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/migrations/0014_execution_step_fetch_scope.py +0 -0
  102. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/migrations/0015_execution_step_apply_engine.py +0 -0
  103. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/migrations/0016_execution_step_query_metrics.py +0 -0
  104. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/migrations/0017_execution_step_row_counters.py +0 -0
  105. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/migrations/0018_execution_run_reconciliation_events.py +0 -0
  106. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/migrations/0019_forwardexecutionstep_query_parameters.py +0 -0
  107. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/migrations/0020_execution_step_operation.py +0 -0
  108. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/migrations/0021_add_fhrpgroup_nqe_map_choice.py +0 -0
  109. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/migrations/0022_alter_forwardnqemap_netbox_model.py +0 -0
  110. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/migrations/0023_split_ip_address_maps.py +0 -0
  111. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/migrations/0024_forwarddeviceanalysis.py +0 -0
  112. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/migrations/0025_device_analysis_netboxmodel.py +0 -0
  113. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/migrations/0026_forwarddeviceanalysis_collection_result.py +0 -0
  114. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/migrations/0027_alter_forwardexecutionrun_backend.py +0 -0
  115. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/migrations/0028_remove_forwardexecutionstep_run_and_more.py +0 -0
  116. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/migrations/0029_forward_parent_device_cf.py +0 -0
  117. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/migrations/0030_forwarddeviceanalysis_cve_ids.py +0 -0
  118. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/migrations/0031_encrypt_source_password.py +0 -0
  119. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/migrations/0032_alter_forwardnqemap_netbox_model.py +0 -0
  120. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/migrations/0033_alter_forwardnqemap_netbox_model.py +0 -0
  121. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/migrations/0034_source_ownership_provenance.py +0 -0
  122. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/migrations/0035_initialize_ownership_control_plane.py +0 -0
  123. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/migrations/0036_protect_ownership_provenance.py +0 -0
  124. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/migrations/0037_merge_identity_and_assignment_provenance.py +0 -0
  125. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/migrations/0038_managed_tag_domain_guard.py +0 -0
  126. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/migrations/0039_forwardingestion_catchup_state.py +0 -0
  127. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/migrations/0040_remove_redundant_nqe_settings.py +0 -0
  128. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/migrations/0041_forwardworkloadstate.py +0 -0
  129. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/migrations/0042_device_generic_relation_guards.py +0 -0
  130. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/migrations/0043_forwardnqemap_diff_contract.py +0 -0
  131. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/migrations/0044_contributor_baseline_cache.py +0 -0
  132. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/migrations/0045_forwardmergeattempt.py +0 -0
  133. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/migrations/0046_alter_forwardnqemap_netbox_model.py +0 -0
  134. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/migrations/0047_ownership_reconciliation_cascade.py +0 -0
  135. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/migrations/0048_forwardingestion_skipped_change_count.py +0 -0
  136. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/migrations/0049_drift_policy_row_shrink_floor.py +0 -0
  137. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/migrations/0050_contributor_baseline_cascade.py +0 -0
  138. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/migrations/0051_ownership_provenance_stamp_nullable.py +0 -0
  139. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/migrations/0052_device_absence_quarantine.py +0 -0
  140. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/migrations/0053_alter_forwardsource_owner.py +0 -0
  141. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/migrations/0053_routing_policy_nqe_map_choices.py +0 -0
  142. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/migrations/0054_aci_tenant_policy_nqe_map_choices.py +0 -0
  143. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/migrations/0054_forwardchange_forwardchangecriterion_and_more.py +0 -0
  144. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/migrations/0055_change_control_approvals.py +0 -0
  145. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/migrations/0055_operator_delete_releases_ownership.py +0 -0
  146. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/migrations/0056_aci_attachment_nqe_map_choices.py +0 -0
  147. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/migrations/0056_routing_policy_nqe_map_choices.py +0 -0
  148. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/migrations/0057_aci_tenant_policy_nqe_map_choices.py +0 -0
  149. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/migrations/0057_nqe_map_last_live_drift.py +0 -0
  150. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/migrations/0058_operator_delete_releases_ownership.py +0 -0
  151. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/migrations/0059_aci_attachment_nqe_map_choices.py +0 -0
  152. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/migrations/0060_merge_maint_2_9_x_history.py +0 -0
  153. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/migrations/0061_static_route_nqe_map_choice.py +0 -0
  154. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/migrations/__init__.py +0 -0
  155. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/models.py +0 -0
  156. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/navigation.py +0 -0
  157. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/__init__.py +0 -0
  158. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/forward_aci_apic_cimc_inventory.nqe +0 -0
  159. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/forward_aci_apic_filters.nqe +0 -0
  160. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/forward_aci_apic_nodes.nqe +0 -0
  161. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/forward_aci_apic_pods.nqe +0 -0
  162. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/forward_aci_app_profiles.nqe +0 -0
  163. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/forward_aci_bridge_domains.nqe +0 -0
  164. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/forward_aci_command_inventory.nqe +0 -0
  165. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/forward_aci_contracts.nqe +0 -0
  166. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/forward_aci_endpoint_groups.nqe +0 -0
  167. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/forward_aci_fabrics.nqe +0 -0
  168. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/forward_aci_filter_entries.nqe +0 -0
  169. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/forward_aci_filters.nqe +0 -0
  170. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/forward_aci_l3outs.nqe +0 -0
  171. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/forward_aci_nodes.nqe +0 -0
  172. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/forward_aci_pods.nqe +0 -0
  173. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/forward_aci_source_readiness.nqe +0 -0
  174. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/forward_aci_static_port_bindings.nqe +0 -0
  175. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/forward_aci_subject_filters.nqe +0 -0
  176. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/forward_aci_subjects.nqe +0 -0
  177. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/forward_aci_tenants.nqe +0 -0
  178. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/forward_aci_vrfs.nqe +0 -0
  179. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/forward_bgp_address_families.nqe +0 -0
  180. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/forward_bgp_peer_address_families.nqe +0 -0
  181. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/forward_bgp_peers.nqe +0 -0
  182. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/forward_cimc_endpoint_inventory.nqe +0 -0
  183. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/forward_config_backup.nqe +0 -0
  184. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/forward_device_analysis.nqe +0 -0
  185. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/forward_device_feature_tags.nqe +0 -0
  186. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/forward_device_feature_tags_with_rules.nqe +0 -0
  187. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/forward_device_models.nqe +0 -0
  188. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/forward_device_models_with_netbox_aliases.nqe +0 -0
  189. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/forward_device_types.nqe +0 -0
  190. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/forward_device_vendors.nqe +0 -0
  191. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/forward_dlm_apic_cimc_inventory_item_software.nqe +0 -0
  192. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/forward_dlm_cves.nqe +0 -0
  193. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/forward_dlm_device_software.nqe +0 -0
  194. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/forward_dlm_hardware_notices.nqe +0 -0
  195. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/forward_dlm_hardware_notices_with_netbox_aliases.nqe +0 -0
  196. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/forward_dlm_inventory_item_software.nqe +0 -0
  197. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/forward_dlm_software_versions.nqe +0 -0
  198. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/forward_dlm_vulnerabilities.nqe +0 -0
  199. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/forward_hsrp_groups.nqe +0 -0
  200. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/forward_inferred_interface_cables.nqe +0 -0
  201. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/forward_interfaces.nqe +0 -0
  202. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/forward_inventory_items.nqe +0 -0
  203. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/forward_ip_addresses_ipv4.nqe +0 -0
  204. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/forward_ip_addresses_ipv6.nqe +0 -0
  205. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/forward_ip_addresses_unassignable_diagnostics.nqe +0 -0
  206. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/forward_locations.nqe +0 -0
  207. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/forward_mac_addresses.nqe +0 -0
  208. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/forward_modules.nqe +0 -0
  209. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/forward_ospf_areas.nqe +0 -0
  210. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/forward_ospf_instances.nqe +0 -0
  211. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/forward_ospf_interfaces.nqe +0 -0
  212. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/forward_peering_sessions.nqe +0 -0
  213. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/forward_platforms.nqe +0 -0
  214. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/forward_prefixes_ipv4.nqe +0 -0
  215. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/forward_prefixes_ipv6.nqe +0 -0
  216. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/forward_routing_community_lists.nqe +0 -0
  217. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/forward_routing_import_diagnostics.nqe +0 -0
  218. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/forward_routing_prefix_lists.nqe +0 -0
  219. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/forward_routing_route_maps.nqe +0 -0
  220. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/forward_static_routes.nqe +0 -0
  221. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/forward_virtual_chassis.nqe +0 -0
  222. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/forward_vlans.nqe +0 -0
  223. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/forward_vrfs.nqe +0 -0
  224. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/queries/netbox_utilities.nqe +0 -0
  225. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/signals.py +0 -0
  226. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/static/forward_netbox/img/fn-logo.svg +0 -0
  227. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tables.py +0 -0
  228. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/template_content.py +0 -0
  229. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/templates/forward_netbox/device_cves.html +0 -0
  230. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/templates/forward_netbox/forwardchange.html +0 -0
  231. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/templates/forward_netbox/forwardchangepolicy.html +0 -0
  232. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/templates/forward_netbox/forwarddeviceanalysis.html +0 -0
  233. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/templates/forward_netbox/forwarddriftpolicy.html +0 -0
  234. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/templates/forward_netbox/forwardingestion.html +0 -0
  235. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/templates/forward_netbox/forwardingestionissue.html +0 -0
  236. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/templates/forward_netbox/forwardnqemap.html +0 -0
  237. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/templates/forward_netbox/forwardsource.html +0 -0
  238. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/templates/forward_netbox/forwardsync.html +0 -0
  239. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/templates/forward_netbox/forwardsync_audit_report.html +0 -0
  240. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/templates/forward_netbox/forwardsync_audits.html +0 -0
  241. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/templates/forward_netbox/forwardsync_delete.html +0 -0
  242. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/templates/forward_netbox/forwardsync_dependency_preview.html +0 -0
  243. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/templates/forward_netbox/forwardsync_drift_report.html +0 -0
  244. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/templates/forward_netbox/forwardsync_health.html +0 -0
  245. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/templates/forward_netbox/forwardsync_module_readiness.html +0 -0
  246. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/templates/forward_netbox/forwardsync_uncovered_devices.html +0 -0
  247. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/templates/forward_netbox/forwardvalidationrun.html +0 -0
  248. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/templates/forward_netbox/htmx/forwardsync_delete_form.html +0 -0
  249. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/templates/forward_netbox/inc/brand_bar.html +0 -0
  250. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/templates/forward_netbox/inc/count_trend.html +0 -0
  251. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/templates/forward_netbox/inc/device_analysis_panel.html +0 -0
  252. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/templates/forward_netbox/inc/device_ownership_panel.html +0 -0
  253. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/templates/forward_netbox/inc/diff.html +0 -0
  254. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/templates/forward_netbox/inc/execution_insights.html +0 -0
  255. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/templates/forward_netbox/inc/logs_pending.html +0 -0
  256. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/templates/forward_netbox/inc/merge_form.html +0 -0
  257. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/templates/forward_netbox/inc/validation_force_allow_form.html +0 -0
  258. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/templates/forward_netbox/partials/change_explainability.html +0 -0
  259. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/templates/forward_netbox/partials/ingestion_all.html +0 -0
  260. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/templates/forward_netbox/partials/ingestion_merge_button.html +0 -0
  261. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/templates/forward_netbox/partials/ingestion_progress.html +0 -0
  262. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/templates/forward_netbox/partials/ingestion_statistics.html +0 -0
  263. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/templates/forward_netbox/partials/ingestion_status.html +0 -0
  264. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/templates/forward_netbox/partials/job_logs.html +0 -0
  265. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/templates/forward_netbox/partials/object_tabs.html +0 -0
  266. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/templates/forward_netbox/partials/stage_switcher_buttons.html +0 -0
  267. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/templates/forward_netbox/partials/validation_force_allow_button.html +0 -0
  268. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/templatetags/__init__.py +0 -0
  269. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/templatetags/forward_netbox_helpers.py +0 -0
  270. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/__init__.py +0 -0
  271. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/fixtures/aci_command_inventory_expected.json +0 -0
  272. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/fixtures/aci_discovery_expected.json +0 -0
  273. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_a_warning_is_not_a_failure.py +0 -0
  274. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_absence_quarantine.py +0 -0
  275. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_absent_configuration_detail.py +0 -0
  276. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_absent_device_does_not_block_tag_domain.py +0 -0
  277. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_accepted_merge_failures.py +0 -0
  278. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_aci_drift_comparison.py +0 -0
  279. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_aci_source_readiness.py +0 -0
  280. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_adapter_drift_scale.py +0 -0
  281. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_api_serializer_base.py +0 -0
  282. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_api_usage.py +0 -0
  283. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_api_views.py +0 -0
  284. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_apic_cimc_readiness_audit_command.py +0 -0
  285. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_apply_identity_audit.py +0 -0
  286. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_audit_report_views.py +0 -0
  287. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_bgp_peer_af_query.py +0 -0
  288. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_bgp_peer_comment_churn.py +0 -0
  289. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_bgp_peer_policy_links.py +0 -0
  290. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_bgp_peer_round_trip_variants.py +0 -0
  291. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_branch_budget_split.py +0 -0
  292. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_branching.py +0 -0
  293. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_brand_bar.py +0 -0
  294. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_builtin_query_id_binding.py +0 -0
  295. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_bulk_adapter_parity.py +0 -0
  296. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_bulk_merge_scale.py +0 -0
  297. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_bundle_diagnostics_parity.py +0 -0
  298. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_button_jobs.py +0 -0
  299. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_cable_drift_comparison.py +0 -0
  300. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_catalogue_models_compare.py +0 -0
  301. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_change_control_evidence.py +0 -0
  302. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_change_control_gates.py +0 -0
  303. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_change_control_policy.py +0 -0
  304. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_change_control_predict.py +0 -0
  305. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_change_control_state_machine.py +0 -0
  306. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_change_explainability_full_counts.py +0 -0
  307. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_changediff_audit.py +0 -0
  308. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_collection_collapse_guard.py +0 -0
  309. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_config_backup.py +0 -0
  310. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_config_backup_folder.py +0 -0
  311. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_config_backup_job_and_health.py +0 -0
  312. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_config_backup_path.py +0 -0
  313. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_config_backup_query.py +0 -0
  314. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_config_backup_result_evidence.py +0 -0
  315. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_constraint_diagnosis.py +0 -0
  316. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_contract_preflight_message.py +0 -0
  317. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_contributor_baseline.py +0 -0
  318. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_converged_models_are_measured.py +0 -0
  319. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_copy_sql_apply_engine.py +0 -0
  320. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_cross_site_vlan_revalidation.py +0 -0
  321. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_crypto.py +0 -0
  322. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_density_observation.py +0 -0
  323. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_dependency_preview_summary.py +0 -0
  324. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_device_analysis_query.py +0 -0
  325. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_device_name_case_identity.py +0 -0
  326. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_device_scope_reconciliation_audit_command.py +0 -0
  327. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_device_scope_tagging.py +0 -0
  328. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_device_site_relabel_identity.py +0 -0
  329. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_diagnostics_readback.py +0 -0
  330. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_diff_removal_allowlist.py +0 -0
  331. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_dlm_catalogue_conflicts.py +0 -0
  332. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_dlm_drift_comparison.py +0 -0
  333. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_dlm_hardware_notice_audit.py +0 -0
  334. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_dlm_integration.py +0 -0
  335. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_dlm_inventoryitem_drift_comparison.py +0 -0
  336. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_drift_comparison.py +0 -0
  337. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_drift_coverage_is_explained.py +0 -0
  338. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_drift_rows_are_distinguishable.py +0 -0
  339. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_durable_workload_state_attribution.py +0 -0
  340. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_empty_comparison_is_not_a_measurement.py +0 -0
  341. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_empty_workload_failure.py +0 -0
  342. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_endpoint_absence_detail.py +0 -0
  343. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_endpoint_ipv4_netmask.py +0 -0
  344. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_execute_by_query_id_without_commit.py +0 -0
  345. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_execution_insights_delete_label.py +0 -0
  346. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_export_redaction.py +0 -0
  347. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_failed_run_model_evidence.py +0 -0
  348. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_fast_baseline.py +0 -0
  349. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_fast_paths_report_when_disabled.py +0 -0
  350. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_fast_paths_subset_runtime.py +0 -0
  351. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_fhrpgroup_drift_comparison.py +0 -0
  352. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_field_reported_integrity_failures.py +0 -0
  353. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_force_allow_override.py +0 -0
  354. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_forms.py +0 -0
  355. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_forward_api.py +0 -0
  356. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_forward_client_errors.py +0 -0
  357. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_forward_client_factory.py +0 -0
  358. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_forward_usage_hooks.py +0 -0
  359. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_full_removal_reconciliation.py +0 -0
  360. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_head_commit_from_listing.py +0 -0
  361. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_health.py +0 -0
  362. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_health_evidence.py +0 -0
  363. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_ingestion_delete.py +0 -0
  364. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_ingestion_is_deletable.py +0 -0
  365. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_ingestion_merge.py +0 -0
  366. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_interface_lookup_query_shape.py +0 -0
  367. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_interface_naming.py +0 -0
  368. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_interface_vlan_audit.py +0 -0
  369. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_inventoryitem_drift_comparison.py +0 -0
  370. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_ip_address_dedup_query.py +0 -0
  371. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_ipaddress_dup_global.py +0 -0
  372. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_issue_diagnosis.py +0 -0
  373. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_issue_rendering.py +0 -0
  374. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_job_liveness.py +0 -0
  375. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_job_queue.py +0 -0
  376. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_jobs.py +0 -0
  377. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_keyerror_names_its_key.py +0 -0
  378. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_license_tier.py +0 -0
  379. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_log_export.py +0 -0
  380. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_logging.py +0 -0
  381. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_merge_observability.py +0 -0
  382. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_merge_profiling.py +0 -0
  383. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_migration_dependencies.py +0 -0
  384. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_migration_lineage.py +0 -0
  385. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_migrations.py +0 -0
  386. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_mixed_model_change_diffs.py +0 -0
  387. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_model_view_routes.py +0 -0
  388. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_models.py +0 -0
  389. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_module_drift_comparison.py +0 -0
  390. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_module_readiness.py +0 -0
  391. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_module_readiness_rollup.py +0 -0
  392. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_nqe_lint_blind_spots.py +0 -0
  393. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_operator_commands.py +0 -0
  394. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_operator_delete_releases_ownership.py +0 -0
  395. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_ospf_neighbour_rows_converge.py +0 -0
  396. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_ownership.py +0 -0
  397. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_ownership_command.py +0 -0
  398. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_ownership_completes_with_preexisting_status_tag.py +0 -0
  399. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_ownership_conflict_reason.py +0 -0
  400. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_ownership_lock_wait.py +0 -0
  401. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_ownership_migration.py +0 -0
  402. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_parameter_signature_drift.py +0 -0
  403. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_peering_drift_comparison.py +0 -0
  404. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_plan_statistics_monotonic.py +0 -0
  405. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_post_sync.py +0 -0
  406. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_preview_isolation.py +0 -0
  407. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_preview_primes_its_lookup_caches.py +0 -0
  408. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_preview_reports_its_cost.py +0 -0
  409. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_preview_runner_satisfies_the_priming_contract.py +0 -0
  410. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_primary_ip_audit.py +0 -0
  411. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_primary_ip_duplicate_names.py +0 -0
  412. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_protected_delete_is_a_skip.py +0 -0
  413. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_protecting_reference_deletes.py +0 -0
  414. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_protecting_relations.py +0 -0
  415. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_provision_preflight.py +0 -0
  416. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_quarantine_cadence.py +0 -0
  417. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_query_binding.py +0 -0
  418. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_query_diff_coverage_audit_command.py +0 -0
  419. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_query_execution_contract.py +0 -0
  420. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_query_id_binding_end_to_end.py +0 -0
  421. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_query_registry.py +0 -0
  422. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_query_signature_drift_check.py +0 -0
  423. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_query_variants.py +0 -0
  424. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_raise_site_is_recorded.py +0 -0
  425. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_refused_deletes_are_not_staged.py +0 -0
  426. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_refused_deletes_are_retried.py +0 -0
  427. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_release_foreign_delete_blockers.py +0 -0
  428. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_release_readiness_audit.py +0 -0
  429. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_reserved_status_tag_adoption.py +0 -0
  430. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_routing_apply_compare_round_trip.py +0 -0
  431. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_routing_catalogue_cleanup.py +0 -0
  432. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_routing_catalogue_drift.py +0 -0
  433. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_routing_catalogue_scope.py +0 -0
  434. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_row_collapsing.py +0 -0
  435. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_row_count_floor.py +0 -0
  436. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_run_size_anomaly.py +0 -0
  437. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_run_size_guard.py +0 -0
  438. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_scheduled_jobs.py +0 -0
  439. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_scope_audit_full.py +0 -0
  440. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_scope_ipam_audit.py +0 -0
  441. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_scope_matched_tags.py +0 -0
  442. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_scope_module_ui.py +0 -0
  443. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_scope_reconciliation_view.py +0 -0
  444. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_scope_shrink_guard.py +0 -0
  445. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_scope_tag_slug_collision.py +0 -0
  446. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_sdk_result_contract.py +0 -0
  447. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_set_based_merge.py +0 -0
  448. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_skip_dependency_direction.py +0 -0
  449. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_skip_names_netbox_row.py +0 -0
  450. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_skip_raisers_name_dependency.py +0 -0
  451. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_skip_rollup_direction.py +0 -0
  452. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_smoke_sync_command.py +0 -0
  453. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_source_parameter_keys_agree.py +0 -0
  454. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_stability_hardening.py +0 -0
  455. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_static_routes_query.py +0 -0
  456. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_stuck_recovery.py +0 -0
  457. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_support_bundle_archive.py +0 -0
  458. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_sync_aci.py +0 -0
  459. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_sync_facade.py +0 -0
  460. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_sync_orchestration.py +0 -0
  461. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_sync_recurrence_pinning.py +0 -0
  462. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_sync_routing_policy.py +0 -0
  463. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_sync_routing_static.py +0 -0
  464. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_sync_runner_contracts.py +0 -0
  465. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_sync_state.py +0 -0
  466. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_taggeditem_drift_comparison.py +0 -0
  467. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_tier3_reducers.py +0 -0
  468. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_tree_model_detection.py +0 -0
  469. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_uncovered_absence_and_trend.py +0 -0
  470. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_uncovered_device_cleanup.py +0 -0
  471. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_uncovered_device_tag.py +0 -0
  472. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_upgrade_reconciliation.py +0 -0
  473. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_validated_runtime_is_declared_once.py +0 -0
  474. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_validation_org_query_audit_command.py +0 -0
  475. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_virtualchassis_drift_comparison.py +0 -0
  476. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_vsys_parent.py +0 -0
  477. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_workload_normalization.py +0 -0
  478. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/tests/test_workload_state.py +0 -0
  479. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/urls.py +0 -0
  480. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/__init__.py +0 -0
  481. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/api_usage.py +0 -0
  482. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/apic_cimc_readiness.py +0 -0
  483. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/apply_engine.py +0 -0
  484. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/apply_engine_copy_sql.py +0 -0
  485. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/apply_engine_decision.py +0 -0
  486. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/apply_identity_audit.py +0 -0
  487. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/audit_reports.py +0 -0
  488. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/branch_budget.py +0 -0
  489. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/branch_lifecycle.py +0 -0
  490. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/branching.py +0 -0
  491. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/bulk_delete.py +0 -0
  492. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/bulk_merge.py +0 -0
  493. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/change_explainability.py +0 -0
  494. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/changediff_audit.py +0 -0
  495. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/config_backup.py +0 -0
  496. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/config_backup_path.py +0 -0
  497. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/constraint_diagnosis.py +0 -0
  498. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/contributor_baseline.py +0 -0
  499. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/crypto.py +0 -0
  500. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/delete_policy.py +0 -0
  501. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/density_learning.py +0 -0
  502. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/device_analysis.py +0 -0
  503. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/direct_changes.py +0 -0
  504. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/dlm_notice_audit.py +0 -0
  505. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/drift_comparison.py +0 -0
  506. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/drift_report.py +0 -0
  507. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/execution_telemetry.py +0 -0
  508. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/executor_base.py +0 -0
  509. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/export_redaction.py +0 -0
  510. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/fast_baseline_models.py +0 -0
  511. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/forward_api.py +0 -0
  512. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/forward_api_impl.py +0 -0
  513. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/forward_client_config.py +0 -0
  514. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/forward_client_errors.py +0 -0
  515. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/forward_client_factory.py +0 -0
  516. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/forward_read_cache.py +0 -0
  517. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/forward_throttle.py +0 -0
  518. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/forward_usage.py +0 -0
  519. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/forward_usage_hooks.py +0 -0
  520. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/full_removal_reconciliation.py +0 -0
  521. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/health.py +0 -0
  522. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/health_apply_fetch.py +0 -0
  523. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/health_checks.py +0 -0
  524. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/health_evidence.py +0 -0
  525. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/health_summary_blocks.py +0 -0
  526. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/ingestion_issues.py +0 -0
  527. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/ingestion_merge.py +0 -0
  528. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/ingestion_presentation.py +0 -0
  529. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/interface_naming.py +0 -0
  530. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/interface_vlan_audit.py +0 -0
  531. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/job_liveness.py +0 -0
  532. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/job_queue.py +0 -0
  533. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/json_safe.py +0 -0
  534. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/license_tier.py +0 -0
  535. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/logging.py +0 -0
  536. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/merge.py +0 -0
  537. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/merge_observability.py +0 -0
  538. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/merge_profiling.py +0 -0
  539. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/merge_set_based.py +0 -0
  540. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/model_contracts.py +0 -0
  541. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/model_validation.py +0 -0
  542. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/module_readiness.py +0 -0
  543. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/ownership.py +0 -0
  544. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/plugin_integrations/__init__.py +0 -0
  545. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/post_sync.py +0 -0
  546. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/primary_ip_audit.py +0 -0
  547. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/query_binding.py +0 -0
  548. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/query_binding_resolution.py +0 -0
  549. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/query_diagnostics.py +0 -0
  550. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/query_execution_contract.py +0 -0
  551. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/query_fetch.py +0 -0
  552. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/query_fetch_execution.py +0 -0
  553. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/query_registry.py +0 -0
  554. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/routing_catalogue_cleanup.py +0 -0
  555. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/routing_dangling_audit.py +0 -0
  556. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/row_collapsing.py +0 -0
  557. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/run_size_anomaly.py +0 -0
  558. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/run_size_guard.py +0 -0
  559. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/runtime_guidance.py +0 -0
  560. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/scope_ipam_audit.py +0 -0
  561. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/single_branch_executor.py +0 -0
  562. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/snapshot_freshness.py +0 -0
  563. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/stuck_recovery.py +0 -0
  564. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/support_bundle_archive.py +0 -0
  565. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/sync.py +0 -0
  566. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/sync_aci.py +0 -0
  567. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/sync_cable.py +0 -0
  568. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/sync_core_models.py +0 -0
  569. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/sync_device.py +0 -0
  570. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/sync_dlm.py +0 -0
  571. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/sync_events.py +0 -0
  572. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/sync_execution.py +0 -0
  573. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/sync_facade.py +0 -0
  574. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/sync_inventory_module.py +0 -0
  575. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/sync_ipam.py +0 -0
  576. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/sync_orchestration.py +0 -0
  577. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/sync_primitives.py +0 -0
  578. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/sync_reporting.py +0 -0
  579. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/sync_routing.py +0 -0
  580. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/sync_routing_policy.py +0 -0
  581. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/sync_routing_static.py +0 -0
  582. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/sync_runner_adapters.py +0 -0
  583. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/sync_runner_contracts.py +0 -0
  584. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/sync_state.py +0 -0
  585. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/tag_contracts.py +0 -0
  586. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/tier3_reducers.py +0 -0
  587. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/upgrade_reconciliation.py +0 -0
  588. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/validation.py +0 -0
  589. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/validation_org_query.py +0 -0
  590. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/version_series.py +0 -0
  591. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/vsys_parent.py +0 -0
  592. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/workload_normalization.py +0 -0
  593. {forward_netbox-3.0.2 → forward_netbox-3.0.4}/forward_netbox/utilities/workload_state.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: forward-netbox
3
- Version: 3.0.2
3
+ Version: 3.0.4
4
4
  Summary: NetBox plugin to sync Forward data into NetBox via built-in NQE queries
5
5
  License: MIT
6
6
  License-File: LICENSE
@@ -36,6 +36,7 @@ Requires-Dist: netbox-routing (>=0.5.0,<0.6.0) ; (python_version >= "3.12" and p
36
36
  Requires-Dist: netbox-validity (==3.6.0) ; (python_version >= "3.12" and python_version < "3.15") and (extra == "validity" or extra == "integrations")
37
37
  Requires-Dist: netboxlabs-netbox-branching (>=1.2.0,<1.3.0) ; python_version >= "3.12" and python_version < "3.15"
38
38
  Requires-Dist: pyzipper (>=0.4.0,<0.5.0)
39
+ Requires-Dist: scrapli (>=2022.7.30,<2026.10) ; (python_version >= "3.12" and python_version < "3.15") and (extra == "validity" or extra == "integrations")
39
40
  Project-URL: Changelog, https://github.com/forwardnetworks/forward-netbox/blob/main/CHANGELOG.md
40
41
  Project-URL: Documentation, https://github.com/forwardnetworks/forward-netbox/tree/main/docs
41
42
  Project-URL: Homepage, https://github.com/forwardnetworks/forward-netbox
@@ -109,15 +110,17 @@ See the
109
110
 
110
111
  ## Release Compatibility
111
112
 
112
- The `3.0.2` release candidate requires NetBox `4.7.x` (tested on `4.7.1`) and `netbox-branching` `1.2.x` (tested on `1.2.0`). Expand for the published release history and candidate notes.
113
+ The `3.0.4` release candidate requires NetBox `4.7.x` (tested on `4.7.1`) and `netbox-branching` `1.2.x` (tested on `1.2.0`). Expand for the published release history and candidate notes.
113
114
 
114
115
  <details>
115
116
  <summary>Release compatibility history</summary>
116
117
 
117
118
  | Plugin Release | NetBox Version | Status |
118
119
  | --- | --- | --- |
119
- | `v3.0.2` | NetBox `4.7.x` supported, tested on `4.7.1`; needs netbox-branching `1.2.x`, tested on `1.2.0` | Release candidate; Port of 2.9.13's PeeringSession crash + endpoint /32 fixes, plus the 3.0.1 upgrade-runtime override fix |
120
- | `v3.0.1` | NetBox `4.7.x` supported, tested on `4.7.1`; needs netbox-branching `1.2.x`, tested on `1.2.0` | Current release; Release candidate; Fix: every fix shipped on the 2.9.x line as 2.9.7 through 2.9.11 now ships on NetBox 4.7 - the 3.x line had none of them. Fix: renaming a device's site in Forward moves the existing device instead of creating a duplicate, devices are matched case-insensitively the way NetBox identifies them, and the new Scope Reconciliation action Merge site-relabel duplicates repairs pairs already created (keeps the older device at the site Forward reports; held pairs are listed with a reason and never pruned). Fix: scope membership is by name, so no in-scope device is called out of scope. Feature: duplicates and other silent problems are no longer silent - a Health check, a sync-page banner, a Scope Reconciliation card and a job-log line. Fix: config backup reaches the repository through the proxy NetBox uses, no longer writes credentials to the worker log, fails when the remote refuses the branch, and names the cause of a failure in the job, Health and the support bundle. Fix: the fast baseline, COPY/SQL and set-based merge run on any subset of the validated plugins. Fix: routing-policy scope counts every device that holds a definition, pending removals are what the next sync removes, and Scope Reconciliation offers Remove out-of-scope routing policy (an allowlisted, gated operator action). Fix: the SDK repository lookup read attributes the forward-sdk RepositoryQuery does not have, so committed-query lookups by path failed against a real Forward; forward-sdk is now 0.1.20. Fix: protection against deleting a sync or ingestion while a job runs, and support bundles and log exports no longer carry operator values such as include-tag names. Feature: the support bundle carries a diagnostics section, and a live query-drift check flags a published query whose parameter list no longer matches this release. Feature: Auto merge stops for review when a run is far larger than the sync has been - only with Auto merge on, only after the sync has finished a run before, and only for a model that stages at least 10,000 changes at 3x the table's size (or 10x the typical earlier run); a held run stays staged, with the ingestion's Merge and Delete actions as Merge anyway and Discard. Feature: Health and the support bundle show Forward's row count next to NetBox's per model, the last three ingestions with job and merge status, statistics and merged changes by model and action, and a BGP peer duplicate count, and flag an abnormal run, a baseline that never completed and a NetBox table far smaller than Forward's. Feature: the config backup folder is configurable (nested folders allowed), Health shows the Validity device_config_path for it, and the last backup reports rows, written, unchanged, unmapped, managed devices with no collected configuration and files in the folder. Fix: the Include unmanaged configuration checkbox never persisted from the source form. Migrations 0053 through 0057 and 0060 adopt the 2.9.x schema history. Org-backed deployments: run Publish Bundled Queries after upgrading, because the interface and IPv4 address queries changed their parameter lists (a stale published copy fails every execution against it until republished) and the three routing-policy queries gained an output column. |
120
+ | `v3.0.4` | NetBox `4.7.x` supported, tested on `4.7.1`; needs netbox-branching `1.2.x`, tested on `1.2.0` | Release candidate; OSPF instance name clashes keep a stable per-process name instead of being skipped; Infoblox and Palo Alto endpoints are named by vendor; netbox-dlm 0.10.1 and 0.10.2 accepted; the UI gate runs on agent-browser; support bundle gains endpoint mask, site placement and fallback-reason figures; tested on NetBox 4.7.2 and netbox-branching 1.2.1 |
121
+ | `v3.0.3` | NetBox `4.7.x` supported, tested on `4.7.1`; needs netbox-branching `1.2.x`, tested on `1.2.0` | Current release; Static routes in the global table import; site-relabel repair releases BGP address families; primary IP falls back to the management address when a tag cannot resolve; interfaces holding a VLAN from a previous site are cleared instead of refused on every sync; scrapli capped so NetBox starts with netbox-validity; OSPF instances named per VRF for netbox-routing 0.5.0; support bundle gains dependency versions, scope-report age, site mismatch, a primary-IP split and mask breakdown, and per-rule issue counts; tested on NetBox 4.7.2 and netbox-branching 1.2.1 |
122
+ | `v3.0.2` | NetBox `4.7.x` supported, tested on `4.7.1`; needs netbox-branching `1.2.x`, tested on `1.2.0` | Superseded by `v3.0.3`; Port of 2.9.13's PeeringSession crash + endpoint /32 fixes, plus the 3.0.1 upgrade-runtime override fix |
123
+ | `v3.0.1` | NetBox `4.7.x` supported, tested on `4.7.1`; needs netbox-branching `1.2.x`, tested on `1.2.0` | Superseded by `v3.0.2`; Release candidate; Fix: every fix shipped on the 2.9.x line as 2.9.7 through 2.9.11 now ships on NetBox 4.7 - the 3.x line had none of them. Fix: renaming a device's site in Forward moves the existing device instead of creating a duplicate, devices are matched case-insensitively the way NetBox identifies them, and the new Scope Reconciliation action Merge site-relabel duplicates repairs pairs already created (keeps the older device at the site Forward reports; held pairs are listed with a reason and never pruned). Fix: scope membership is by name, so no in-scope device is called out of scope. Feature: duplicates and other silent problems are no longer silent - a Health check, a sync-page banner, a Scope Reconciliation card and a job-log line. Fix: config backup reaches the repository through the proxy NetBox uses, no longer writes credentials to the worker log, fails when the remote refuses the branch, and names the cause of a failure in the job, Health and the support bundle. Fix: the fast baseline, COPY/SQL and set-based merge run on any subset of the validated plugins. Fix: routing-policy scope counts every device that holds a definition, pending removals are what the next sync removes, and Scope Reconciliation offers Remove out-of-scope routing policy (an allowlisted, gated operator action). Fix: the SDK repository lookup read attributes the forward-sdk RepositoryQuery does not have, so committed-query lookups by path failed against a real Forward; forward-sdk is now 0.1.20. Fix: protection against deleting a sync or ingestion while a job runs, and support bundles and log exports no longer carry operator values such as include-tag names. Feature: the support bundle carries a diagnostics section, and a live query-drift check flags a published query whose parameter list no longer matches this release. Feature: Auto merge stops for review when a run is far larger than the sync has been - only with Auto merge on, only after the sync has finished a run before, and only for a model that stages at least 10,000 changes at 3x the table's size (or 10x the typical earlier run); a held run stays staged, with the ingestion's Merge and Delete actions as Merge anyway and Discard. Feature: Health and the support bundle show Forward's row count next to NetBox's per model, the last three ingestions with job and merge status, statistics and merged changes by model and action, and a BGP peer duplicate count, and flag an abnormal run, a baseline that never completed and a NetBox table far smaller than Forward's. Feature: the config backup folder is configurable (nested folders allowed), Health shows the Validity device_config_path for it, and the last backup reports rows, written, unchanged, unmapped, managed devices with no collected configuration and files in the folder. Fix: the Include unmanaged configuration checkbox never persisted from the source form. Migrations 0053 through 0057 and 0060 adopt the 2.9.x schema history. Org-backed deployments: run Publish Bundled Queries after upgrading, because the interface and IPv4 address queries changed their parameter lists (a stale published copy fails every execution against it until republished) and the three routing-policy queries gained an output column. |
121
124
  | `v3.0.0` | NetBox `4.7.x` supported, tested on `4.7.0`; needs netbox-branching `1.2.x`, tested on `1.2.0` | Superseded by `v3.0.1`; NetBox 4.7 with netbox-branching 1.2, and change control gated on what Forward saw before and after the change. |
122
125
  | `v2.9.2` | `4.6.x` (>= `4.6.5`) supported, tested on `4.6.8`; needs netbox-branching `1.1.x`, tested on `1.1.2` | Superseded by `v3.0.0`; Drift is measured exactly for every fetched model, the uncovered-device count says why it grows and warns when it does, and five delete and diagnostic defects are closed. |
123
126
  | `v2.9.1` | `4.6.x` (>= `4.6.5`) supported, tested on `4.6.8`; needs netbox-branching `1.1.x`, tested on `1.1.2` | Superseded by `v2.9.2`; Accepts netbox-branching 1.1.3 and records the validated runtime in the lockfile. |
@@ -64,15 +64,17 @@ See the
64
64
 
65
65
  ## Release Compatibility
66
66
 
67
- The `3.0.2` release candidate requires NetBox `4.7.x` (tested on `4.7.1`) and `netbox-branching` `1.2.x` (tested on `1.2.0`). Expand for the published release history and candidate notes.
67
+ The `3.0.4` release candidate requires NetBox `4.7.x` (tested on `4.7.1`) and `netbox-branching` `1.2.x` (tested on `1.2.0`). Expand for the published release history and candidate notes.
68
68
 
69
69
  <details>
70
70
  <summary>Release compatibility history</summary>
71
71
 
72
72
  | Plugin Release | NetBox Version | Status |
73
73
  | --- | --- | --- |
74
- | `v3.0.2` | NetBox `4.7.x` supported, tested on `4.7.1`; needs netbox-branching `1.2.x`, tested on `1.2.0` | Release candidate; Port of 2.9.13's PeeringSession crash + endpoint /32 fixes, plus the 3.0.1 upgrade-runtime override fix |
75
- | `v3.0.1` | NetBox `4.7.x` supported, tested on `4.7.1`; needs netbox-branching `1.2.x`, tested on `1.2.0` | Current release; Release candidate; Fix: every fix shipped on the 2.9.x line as 2.9.7 through 2.9.11 now ships on NetBox 4.7 - the 3.x line had none of them. Fix: renaming a device's site in Forward moves the existing device instead of creating a duplicate, devices are matched case-insensitively the way NetBox identifies them, and the new Scope Reconciliation action Merge site-relabel duplicates repairs pairs already created (keeps the older device at the site Forward reports; held pairs are listed with a reason and never pruned). Fix: scope membership is by name, so no in-scope device is called out of scope. Feature: duplicates and other silent problems are no longer silent - a Health check, a sync-page banner, a Scope Reconciliation card and a job-log line. Fix: config backup reaches the repository through the proxy NetBox uses, no longer writes credentials to the worker log, fails when the remote refuses the branch, and names the cause of a failure in the job, Health and the support bundle. Fix: the fast baseline, COPY/SQL and set-based merge run on any subset of the validated plugins. Fix: routing-policy scope counts every device that holds a definition, pending removals are what the next sync removes, and Scope Reconciliation offers Remove out-of-scope routing policy (an allowlisted, gated operator action). Fix: the SDK repository lookup read attributes the forward-sdk RepositoryQuery does not have, so committed-query lookups by path failed against a real Forward; forward-sdk is now 0.1.20. Fix: protection against deleting a sync or ingestion while a job runs, and support bundles and log exports no longer carry operator values such as include-tag names. Feature: the support bundle carries a diagnostics section, and a live query-drift check flags a published query whose parameter list no longer matches this release. Feature: Auto merge stops for review when a run is far larger than the sync has been - only with Auto merge on, only after the sync has finished a run before, and only for a model that stages at least 10,000 changes at 3x the table's size (or 10x the typical earlier run); a held run stays staged, with the ingestion's Merge and Delete actions as Merge anyway and Discard. Feature: Health and the support bundle show Forward's row count next to NetBox's per model, the last three ingestions with job and merge status, statistics and merged changes by model and action, and a BGP peer duplicate count, and flag an abnormal run, a baseline that never completed and a NetBox table far smaller than Forward's. Feature: the config backup folder is configurable (nested folders allowed), Health shows the Validity device_config_path for it, and the last backup reports rows, written, unchanged, unmapped, managed devices with no collected configuration and files in the folder. Fix: the Include unmanaged configuration checkbox never persisted from the source form. Migrations 0053 through 0057 and 0060 adopt the 2.9.x schema history. Org-backed deployments: run Publish Bundled Queries after upgrading, because the interface and IPv4 address queries changed their parameter lists (a stale published copy fails every execution against it until republished) and the three routing-policy queries gained an output column. |
74
+ | `v3.0.4` | NetBox `4.7.x` supported, tested on `4.7.1`; needs netbox-branching `1.2.x`, tested on `1.2.0` | Release candidate; OSPF instance name clashes keep a stable per-process name instead of being skipped; Infoblox and Palo Alto endpoints are named by vendor; netbox-dlm 0.10.1 and 0.10.2 accepted; the UI gate runs on agent-browser; support bundle gains endpoint mask, site placement and fallback-reason figures; tested on NetBox 4.7.2 and netbox-branching 1.2.1 |
75
+ | `v3.0.3` | NetBox `4.7.x` supported, tested on `4.7.1`; needs netbox-branching `1.2.x`, tested on `1.2.0` | Current release; Static routes in the global table import; site-relabel repair releases BGP address families; primary IP falls back to the management address when a tag cannot resolve; interfaces holding a VLAN from a previous site are cleared instead of refused on every sync; scrapli capped so NetBox starts with netbox-validity; OSPF instances named per VRF for netbox-routing 0.5.0; support bundle gains dependency versions, scope-report age, site mismatch, a primary-IP split and mask breakdown, and per-rule issue counts; tested on NetBox 4.7.2 and netbox-branching 1.2.1 |
76
+ | `v3.0.2` | NetBox `4.7.x` supported, tested on `4.7.1`; needs netbox-branching `1.2.x`, tested on `1.2.0` | Superseded by `v3.0.3`; Port of 2.9.13's PeeringSession crash + endpoint /32 fixes, plus the 3.0.1 upgrade-runtime override fix |
77
+ | `v3.0.1` | NetBox `4.7.x` supported, tested on `4.7.1`; needs netbox-branching `1.2.x`, tested on `1.2.0` | Superseded by `v3.0.2`; Release candidate; Fix: every fix shipped on the 2.9.x line as 2.9.7 through 2.9.11 now ships on NetBox 4.7 - the 3.x line had none of them. Fix: renaming a device's site in Forward moves the existing device instead of creating a duplicate, devices are matched case-insensitively the way NetBox identifies them, and the new Scope Reconciliation action Merge site-relabel duplicates repairs pairs already created (keeps the older device at the site Forward reports; held pairs are listed with a reason and never pruned). Fix: scope membership is by name, so no in-scope device is called out of scope. Feature: duplicates and other silent problems are no longer silent - a Health check, a sync-page banner, a Scope Reconciliation card and a job-log line. Fix: config backup reaches the repository through the proxy NetBox uses, no longer writes credentials to the worker log, fails when the remote refuses the branch, and names the cause of a failure in the job, Health and the support bundle. Fix: the fast baseline, COPY/SQL and set-based merge run on any subset of the validated plugins. Fix: routing-policy scope counts every device that holds a definition, pending removals are what the next sync removes, and Scope Reconciliation offers Remove out-of-scope routing policy (an allowlisted, gated operator action). Fix: the SDK repository lookup read attributes the forward-sdk RepositoryQuery does not have, so committed-query lookups by path failed against a real Forward; forward-sdk is now 0.1.20. Fix: protection against deleting a sync or ingestion while a job runs, and support bundles and log exports no longer carry operator values such as include-tag names. Feature: the support bundle carries a diagnostics section, and a live query-drift check flags a published query whose parameter list no longer matches this release. Feature: Auto merge stops for review when a run is far larger than the sync has been - only with Auto merge on, only after the sync has finished a run before, and only for a model that stages at least 10,000 changes at 3x the table's size (or 10x the typical earlier run); a held run stays staged, with the ingestion's Merge and Delete actions as Merge anyway and Discard. Feature: Health and the support bundle show Forward's row count next to NetBox's per model, the last three ingestions with job and merge status, statistics and merged changes by model and action, and a BGP peer duplicate count, and flag an abnormal run, a baseline that never completed and a NetBox table far smaller than Forward's. Feature: the config backup folder is configurable (nested folders allowed), Health shows the Validity device_config_path for it, and the last backup reports rows, written, unchanged, unmapped, managed devices with no collected configuration and files in the folder. Fix: the Include unmanaged configuration checkbox never persisted from the source form. Migrations 0053 through 0057 and 0060 adopt the 2.9.x schema history. Org-backed deployments: run Publish Bundled Queries after upgrading, because the interface and IPv4 address queries changed their parameter lists (a stale published copy fails every execution against it until republished) and the three routing-policy queries gained an output column. |
76
78
  | `v3.0.0` | NetBox `4.7.x` supported, tested on `4.7.0`; needs netbox-branching `1.2.x`, tested on `1.2.0` | Superseded by `v3.0.1`; NetBox 4.7 with netbox-branching 1.2, and change control gated on what Forward saw before and after the change. |
77
79
  | `v2.9.2` | `4.6.x` (>= `4.6.5`) supported, tested on `4.6.8`; needs netbox-branching `1.1.x`, tested on `1.1.2` | Superseded by `v3.0.0`; Drift is measured exactly for every fetched model, the uncovered-device count says why it grows and warns when it does, and five delete and diagnostic defects are closed. |
78
80
  | `v2.9.1` | `4.6.x` (>= `4.6.5`) supported, tested on `4.6.8`; needs netbox-branching `1.1.x`, tested on `1.1.2` | Superseded by `v2.9.2`; Accepts netbox-branching 1.1.3 and records the validated runtime in the lockfile. |
@@ -5,7 +5,7 @@ class NetboxForwardConfig(PluginConfig):
5
5
  name = "forward_netbox"
6
6
  verbose_name = "Forward"
7
7
  description = "Sync Forward data into NetBox using built-in NQE queries."
8
- version = "3.0.2"
8
+ version = "3.0.4"
9
9
  base_url = "forward"
10
10
  min_version = "4.7.0"
11
11
  max_version = "4.7.99"
@@ -27,7 +27,7 @@ from forward_netbox.utilities.ownership import required_ownership_domains
27
27
 
28
28
 
29
29
  class Command(BaseCommand):
30
- help = "Seed synthetic Forward NetBox records for the Playwright UI harness."
30
+ help = "Seed synthetic Forward NetBox records for the agent-browser UI harness."
31
31
 
32
32
  def add_arguments(self, parser):
33
33
  parser.add_argument(
@@ -59,7 +59,7 @@ class Command(BaseCommand):
59
59
  if os.getenv("FORWARD_UI_HARNESS_ISOLATED", "").lower() != "true":
60
60
  raise CommandError(
61
61
  "Synthetic UI fixtures may only be seeded in the isolated "
62
- "`invoke playwright-test` runtime."
62
+ "`invoke ui-test` runtime."
63
63
  )
64
64
  user = self._ensure_superuser(
65
65
  username=options["username"],
@@ -111,8 +111,17 @@ foreach row in (
111
111
  // overlay like Avocent/Opengear (these are ordinary SNMP-GENERIC-class
112
112
  // endpoints, ungated by sync_generic_endpoints), just a manufacturer
113
113
  // signal for when SNMP returned no sysDescr/sysObjectID to read one from.
114
- let isInfoblox = matches(endpointProfileName, "*infoblox*")
115
- let isPaloAlto = matches(endpointProfileName, "*pano*")
114
+ // These appliances answer sysDescr, but with text that does not name the
115
+ // vendor: an Infoblox NIOS box reports `Linux <hostname> <kernel>` (so the
116
+ // first token read as the manufacturer made it "Linux"), and a Panorama
117
+ // reports `Palo Alto Networks M-Series Appliance` (first token "Palo").
118
+ // The vendor's enterprise OID and the profile name identify them instead.
119
+ let isInfoblox = matches(sysObjId, "1.3.6.1.4.1.7779.*")
120
+ || matches(sdLower, "*infoblox*")
121
+ || matches(endpointProfileName, "*infoblox*")
122
+ let isPaloAlto = matches(sysObjId, "1.3.6.1.4.1.25461.*")
123
+ || matches(sdLower, "*palo alto*")
124
+ || matches(endpointProfileName, "*pano*")
116
125
  || matches(endpointProfileName, "*panorama*")
117
126
  // Manufacturer: the overlay/profile match when one applies; else the
118
127
  // first token of the cleaned sysDescr; "Unknown" only when none of the
@@ -120,9 +129,9 @@ foreach row in (
120
129
  // profile is generic).
121
130
  let ep_manuf_raw = if isAvocent then "Avocent"
122
131
  else if isOpengear then "Opengear"
123
- else if hasDescr then substring(replaceRegexMatches(sysDescrClean, re` .*`, ""), 0, 100)
124
132
  else if isInfoblox then "Infoblox"
125
133
  else if isPaloAlto then "Palo Alto Networks"
134
+ else if hasDescr then substring(replaceRegexMatches(sysDescrClean, re` .*`, ""), 0, 100)
126
135
  else "Unknown"
127
136
  let ep_manuf = if ep_manuf_raw == "" then "Unknown" else ep_manuf_raw
128
137
  let ep_manuf_slug_raw = slugify(ep_manuf)
@@ -152,8 +152,17 @@ foreach row in (
152
152
  // overlay like Avocent/Opengear (these are ordinary SNMP-GENERIC-class
153
153
  // endpoints, ungated by sync_generic_endpoints), just a manufacturer
154
154
  // signal for when SNMP returned no sysDescr/sysObjectID to read one from.
155
- let isInfoblox = matches(endpointProfileName, "*infoblox*")
156
- let isPaloAlto = matches(endpointProfileName, "*pano*")
155
+ // These appliances answer sysDescr, but with text that does not name the
156
+ // vendor: an Infoblox NIOS box reports `Linux <hostname> <kernel>` (so the
157
+ // first token read as the manufacturer made it "Linux"), and a Panorama
158
+ // reports `Palo Alto Networks M-Series Appliance` (first token "Palo").
159
+ // The vendor's enterprise OID and the profile name identify them instead.
160
+ let isInfoblox = matches(sysObjId, "1.3.6.1.4.1.7779.*")
161
+ || matches(sdLower, "*infoblox*")
162
+ || matches(endpointProfileName, "*infoblox*")
163
+ let isPaloAlto = matches(sysObjId, "1.3.6.1.4.1.25461.*")
164
+ || matches(sdLower, "*palo alto*")
165
+ || matches(endpointProfileName, "*pano*")
157
166
  || matches(endpointProfileName, "*panorama*")
158
167
  // Manufacturer: the overlay/profile match when one applies; else the
159
168
  // first token of the cleaned sysDescr; "Unknown" only when none of the
@@ -161,9 +170,9 @@ foreach row in (
161
170
  // profile is generic).
162
171
  let ep_manuf_raw = if isAvocent then "Avocent"
163
172
  else if isOpengear then "Opengear"
164
- else if hasDescr then substring(replaceRegexMatches(sysDescrClean, re` .*`, ""), 0, 100)
165
173
  else if isInfoblox then "Infoblox"
166
174
  else if isPaloAlto then "Palo Alto Networks"
175
+ else if hasDescr then substring(replaceRegexMatches(sysDescrClean, re` .*`, ""), 0, 100)
167
176
  else "Unknown"
168
177
  let ep_manuf = if ep_manuf_raw == "" then "Unknown" else ep_manuf_raw
169
178
  let ep_manuf_slug_raw = slugify(ep_manuf)
@@ -489,7 +489,11 @@
489
489
  </p>
490
490
  <ul class="mb-0">
491
491
  {% for entry in site_relabel_pairs.held_by_reason %}
492
- <li><strong>{{ entry.count }}</strong> - {{ entry.remedy|default:entry.reason }}</li>
492
+ <li><strong>{{ entry.count }}</strong> - {{ entry.remedy|default:entry.reason }}
493
+ {% if entry.names %}
494
+ <div class="text-muted small">{{ entry.names|join:", " }}{% if entry.more_names %}, +{{ entry.more_names }} {% trans "more" %}{% endif %}</div>
495
+ {% endif %}
496
+ </li>
493
497
  {% endfor %}
494
498
  </ul>
495
499
  {% endif %}
@@ -174,6 +174,66 @@ class ForwardBulkOrmApplyEngineTest(TestCase):
174
174
  self.assertEqual(Site.objects.filter(name="Bad").count(), 0)
175
175
  runner._record_issue.assert_called_once()
176
176
 
177
+ def test_isolate_bulk_objects_indexes_a_rescued_shard_once(self):
178
+ # A shard that fell back to row-by-row saves must cost the search cache
179
+ # one update, not one per row: every "Search cache update" is a queued
180
+ # job, and a large shard used to queue thousands.
181
+ from netbox.search import deferred
182
+
183
+ from forward_netbox.utilities.apply_engine_bulk import _isolate_bulk_objects
184
+
185
+ flushed = []
186
+ sites = [Site(name=f"Rescued {i}", slug=f"rescued-{i}") for i in range(25)]
187
+
188
+ with patch.object(
189
+ deferred, "_flush", lambda batch, using: flushed.append(dict(batch))
190
+ ):
191
+ with self.captureOnCommitCallbacks(execute=True):
192
+ _isolate_bulk_objects(
193
+ Site, sites, "create", self._runner(), "dcim.site"
194
+ )
195
+
196
+ self.assertEqual(Site.objects.filter(slug__startswith="rescued-").count(), 25)
197
+ self.assertEqual(len(flushed), 1)
198
+ self.assertEqual(len(flushed[0]), 25)
199
+
200
+ def test_isolate_bulk_objects_does_not_index_a_row_that_failed(self):
201
+ from netbox.search import deferred
202
+
203
+ from forward_netbox.utilities.apply_engine_bulk import _isolate_bulk_objects
204
+
205
+ Site.objects.create(name="Taken", slug="taken")
206
+ flushed = []
207
+ good = Site(name="Good", slug="good")
208
+ bad = Site(name="Bad", slug="taken") # duplicate slug -> IntegrityError
209
+
210
+ with patch.object(
211
+ deferred, "_flush", lambda batch, using: flushed.append(dict(batch))
212
+ ):
213
+ with self.captureOnCommitCallbacks(execute=True):
214
+ _isolate_bulk_objects(
215
+ Site, [good, bad], "create", self._runner(), "dcim.site"
216
+ )
217
+
218
+ indexed_pks = {pk for batch in flushed for (_type, pk) in batch}
219
+ self.assertEqual(indexed_pks, {good.pk})
220
+
221
+ def test_isolate_bulk_objects_restores_the_search_handler(self):
222
+ from netbox.search.backends import search_backend
223
+
224
+ from forward_netbox.utilities.apply_engine_bulk import _isolate_bulk_objects
225
+
226
+ before = search_backend.caching_handler
227
+ _isolate_bulk_objects(
228
+ Site,
229
+ [Site(name="Restore", slug="restore")],
230
+ "create",
231
+ self._runner(),
232
+ "dcim.site",
233
+ )
234
+ self.assertEqual(search_backend.caching_handler, before)
235
+ self.assertNotIn("caching_handler", vars(search_backend))
236
+
177
237
  def test_bulk_orm_creates_and_updates_manufacturers(self):
178
238
  self.sync.parameters["enable_bulk_orm"] = True
179
239
  self.sync.save(update_fields=["parameters"])
@@ -4516,8 +4516,19 @@ class Phase4BulkStageTest(CleanTransactionTestCase):
4516
4516
  request_id=merge_request_id,
4517
4517
  )
4518
4518
  # The member is audited as CREATE plus the internal deferred-LAG UPDATE;
4519
- # the two audit rows still count as one logical branch change.
4520
- self.assertEqual(audits.count(), 4)
4519
+ # the two audit rows still count as one logical branch change. Deleting
4520
+ # the cable also clears the parent's cached cable fields (`cable`,
4521
+ # `_path`, `cable_end`), which netbox-branching 1.2.1 records as its own
4522
+ # UPDATE: five rows, still all attributed to the invoking user.
4523
+ self.assertEqual(audits.count(), 5)
4524
+ self.assertEqual(
4525
+ audits.filter(
4526
+ changed_object_type=interface_type,
4527
+ changed_object_id=main_parent.pk,
4528
+ action="update",
4529
+ ).count(),
4530
+ 2,
4531
+ )
4521
4532
  self.assertEqual(
4522
4533
  set(audits.values_list("user_id", flat=True)), {invoking_user.pk}
4523
4534
  )
@@ -4530,7 +4541,7 @@ class Phase4BulkStageTest(CleanTransactionTestCase):
4530
4541
  )
4531
4542
  self.assertEqual(
4532
4543
  branch.get_merged_changes().filter(pk__in=audits).count(),
4533
- 4,
4544
+ 5,
4534
4545
  )
4535
4546
  self.assertEqual(
4536
4547
  list(
@@ -0,0 +1,208 @@
1
+ # The support bundle answers the questions a customer report actually asks.
2
+ #
3
+ # A customer's report this cycle could not be matched to its bundle: a three-day-old
4
+ # scope report sat beside a same-day sync, the primary-IP count had no split to
5
+ # reconcile against the device list, 147 issues had to be tallied by hand to find
6
+ # that 130 were one rule, and a dependency release that stopped NetBox starting left
7
+ # no version in the file. These pin the figures that close each gap, and that the
8
+ # export still carries counts rather than names.
9
+ import json
10
+
11
+ from dcim.models import Device
12
+ from dcim.models import DeviceRole
13
+ from dcim.models import DeviceType
14
+ from dcim.models import Manufacturer
15
+ from dcim.models import Site
16
+ from django.test import TestCase
17
+ from extras.models import Tag
18
+
19
+ from forward_netbox.models import ForwardDeviceIdentity
20
+ from forward_netbox.models import ForwardIngestion
21
+ from forward_netbox.models import ForwardIngestionIssue
22
+ from forward_netbox.models import ForwardSource
23
+ from forward_netbox.models import ForwardSync
24
+ from forward_netbox.utilities.bundle_diagnostics import bundle_diagnostics
25
+ from forward_netbox.utilities.export_redaction import export_safe_payload
26
+ from forward_netbox.views import _environment_bundle_payload
27
+ from forward_netbox.views import _ingestion_issue_bundle_payload
28
+ from forward_netbox.views import _primary_ip_bundle_payload
29
+ from forward_netbox.views import _scope_reconciliation_bundle_payload
30
+
31
+
32
+ class BundleTriageDiagnosticsTest(TestCase):
33
+ def setUp(self):
34
+ self.site = Site.objects.create(name="Secret Street Site", slug="secret")
35
+ mfr = Manufacturer.objects.create(name="Cisco", slug="cisco")
36
+ self.device_type = DeviceType.objects.create(
37
+ manufacturer=mfr, model="M1", slug="m1"
38
+ )
39
+ self.role = DeviceRole.objects.create(name="firewall", slug="firewall")
40
+ source = ForwardSource.objects.create(
41
+ name="src", url="https://fwd.example.invalid"
42
+ )
43
+ self.sync = ForwardSync.objects.create(name="sync", source=source)
44
+
45
+ def _device(self, name, *, managed=True, tag=None):
46
+ device = Device.objects.create(
47
+ name=name,
48
+ site=self.site,
49
+ device_type=self.device_type,
50
+ role=self.role,
51
+ status="active",
52
+ )
53
+ if managed:
54
+ ForwardDeviceIdentity.objects.create(
55
+ sync=self.sync, device=device, source_device_key=name
56
+ )
57
+ if tag:
58
+ device.tags.add(Tag.objects.get_or_create(name=tag, slug=tag.lower())[0])
59
+ return device
60
+
61
+ def test_the_primary_ip_count_is_split_so_it_can_be_reconciled(self):
62
+ self._device("fw-uncovered", tag="forward-uncovered")
63
+ self._device("fw-mgmt", tag="Mgmt_Vl211")
64
+ self._device("fw-plain")
65
+ self._device("unmanaged", managed=False)
66
+
67
+ payload = _primary_ip_bundle_payload(self.sync)
68
+
69
+ self.assertEqual(payload["sync_devices"], 3)
70
+ self.assertEqual(payload["without_primary_ip"], 3)
71
+ split = payload["without_primary_ip_split"]
72
+ self.assertEqual(split["tagged_uncovered"], 1)
73
+ self.assertEqual(split["with_a_mgmt_tag"], 1)
74
+ self.assertEqual(split["with_no_ip_at_all"], 3)
75
+ self.assertEqual(split["with_an_interface_ip"], 0)
76
+ # The figure on the device list covers devices this sync does not own.
77
+ self.assertEqual(payload["netbox_devices_without_primary_ip"], 4)
78
+
79
+ def test_primary_addresses_are_counted_by_mask_and_host_masks_by_role(self):
80
+ from ipam.models import IPAddress
81
+
82
+ loopback = self._device("fw-loopback")
83
+ subnet = self._device("fw-subnet")
84
+ for device, address in ((loopback, "10.0.0.1/32"), (subnet, "10.0.1.1/24")):
85
+ ip = IPAddress.objects.create(address=address)
86
+ Device.objects.filter(pk=device.pk).update(primary_ip4=ip)
87
+
88
+ masks = _primary_ip_bundle_payload(self.sync)["primary_ip4_prefix_lengths"]
89
+
90
+ self.assertEqual(
91
+ {row["prefix_length"]: row["devices"] for row in masks["by_prefix_length"]},
92
+ {32: 1, 24: 1},
93
+ )
94
+ self.assertEqual(
95
+ masks["host_mask_by_role"], [{"role": "firewall", "devices": 1}]
96
+ )
97
+
98
+ def test_interface_addresses_are_counted_by_mask_and_the_default_site_is_listed(
99
+ self,
100
+ ):
101
+ from dcim.models import Interface
102
+ from ipam.models import IPAddress
103
+
104
+ default = Site.objects.create(name="Default", slug="default")
105
+ endpoint = self._device("endpoint-1")
106
+ Device.objects.filter(pk=endpoint.pk).update(site=default)
107
+ switch = self._device("switch-1")
108
+ for device, address in ((endpoint, "10.0.0.9/32"), (switch, "10.0.1.1/24")):
109
+ interface = Interface.objects.create(
110
+ device=device, name="Gi0/1", type="1000base-t"
111
+ )
112
+ IPAddress.objects.create(address=address, assigned_object=interface)
113
+
114
+ payload = _primary_ip_bundle_payload(self.sync)
115
+
116
+ masks = payload["interface_ip4_prefix_lengths"]
117
+ self.assertEqual(
118
+ {
119
+ row["prefix_length"]: row["addresses"]
120
+ for row in masks["by_prefix_length"]
121
+ },
122
+ {32: 1, 24: 1},
123
+ )
124
+ self.assertEqual(
125
+ masks["host_mask_by_role"], [{"role": "firewall", "addresses": 1}]
126
+ )
127
+ placement = payload["site_placement"]
128
+ self.assertEqual(placement["at_default_site"], 1)
129
+ self.assertEqual(placement["at_default_site_by_role"], {"firewall": 1})
130
+ self.assertEqual(placement["at_default_site_without_primary_ip"], 1)
131
+ self.assertNotIn("endpoint-1", json.dumps(payload))
132
+
133
+ def test_issues_are_tallied_by_model_exception_and_rule_over_every_row(self):
134
+ ingestion = ForwardIngestion.objects.create(sync=self.sync)
135
+ for _ in range(3):
136
+ ForwardIngestionIssue.objects.create(
137
+ ingestion=ingestion,
138
+ model="dcim.interface",
139
+ exception="ValidationError",
140
+ message="Merge failed",
141
+ raw_data={"validation_rules": ["untagged-vlan-outside-device-site"]},
142
+ )
143
+ ForwardIngestionIssue.objects.create(
144
+ ingestion=ingestion,
145
+ model="dcim.site",
146
+ exception="ForwardDependencySkipError",
147
+ message="skipped",
148
+ raw_data={},
149
+ )
150
+
151
+ summary = _ingestion_issue_bundle_payload(ingestion)["summary"]
152
+
153
+ self.assertEqual(summary["counted"], 4)
154
+ self.assertEqual(
155
+ summary["by_model_and_exception"][0],
156
+ {"model": "dcim.interface", "exception": "ValidationError", "count": 3},
157
+ )
158
+ self.assertEqual(
159
+ summary["by_validation_rule"],
160
+ [
161
+ {
162
+ "model": "dcim.interface",
163
+ "rule": "untagged-vlan-outside-device-site",
164
+ "count": 3,
165
+ }
166
+ ],
167
+ )
168
+
169
+ def test_the_environment_names_the_dependency_versions(self):
170
+ deps = _environment_bundle_payload()["dependency_versions"]
171
+
172
+ for name in ("scrapli", "scrapli-netconf", "forward-sdk", "django"):
173
+ self.assertIn(name, deps)
174
+ # A package that is not installed reads None, never an error.
175
+ self.assertTrue(all(v is None or isinstance(v, str) for v in deps.values()))
176
+ self.assertTrue(deps["django"])
177
+
178
+ def test_a_missing_scope_report_has_no_age_rather_than_a_wrong_one(self):
179
+ payload = _scope_reconciliation_bundle_payload(self.sync)
180
+
181
+ self.assertIsNone(payload["generated_at"])
182
+ self.assertIsNone(payload["age_hours"])
183
+ self.assertIsNone(payload["older_than_last_sync"])
184
+
185
+ def test_routing_name_collisions_reports_whether_the_plugin_is_there(self):
186
+ out = bundle_diagnostics(self.sync)
187
+
188
+ self.assertEqual(out["errors"], {})
189
+ collisions = out["routing_name_collisions"]
190
+ self.assertIn("installed", collisions)
191
+ if collisions["installed"]:
192
+ self.assertEqual(collisions["duplicate_name_groups"], 0)
193
+
194
+ def test_the_new_figures_export_without_names(self):
195
+ self._device("customer-firewall-01", tag="forward-uncovered")
196
+ text = json.dumps(
197
+ export_safe_payload(
198
+ {
199
+ "primary_ip": _primary_ip_bundle_payload(self.sync),
200
+ "diagnostics": bundle_diagnostics(self.sync),
201
+ "environment": _environment_bundle_payload(),
202
+ }
203
+ ),
204
+ default=str,
205
+ )
206
+
207
+ self.assertNotIn("customer-firewall-01", text)
208
+ self.assertNotIn("Secret Street", text)
@@ -421,6 +421,32 @@ class EndpointBranchIncludeScopeTest(SimpleTestCase):
421
421
  params = _default_query_parameters(filename)
422
422
  self.assertIs(params["sync_generic_endpoints"], False, filename)
423
423
 
424
+ def test_vendor_overlays_name_the_manufacturer_before_the_sysdescr_token(self):
425
+ # An Infoblox box reports `Linux <host> <kernel>` and a Panorama reports
426
+ # `Palo Alto Networks ...`, so reading the first sysDescr token first
427
+ # made them "Linux" and "Palo". The enterprise OID and the profile name
428
+ # come before that token.
429
+ for filename in (
430
+ "forward_devices.nqe",
431
+ "forward_devices_with_netbox_aliases.nqe",
432
+ ):
433
+ endpoint_branch = _read_query(filename).split("network.endpoints", 1)[1]
434
+ self.assertIn('matches(sysObjId, "1.3.6.1.4.1.7779.*")', endpoint_branch)
435
+ self.assertIn('matches(sysObjId, "1.3.6.1.4.1.25461.*")', endpoint_branch)
436
+ chain = endpoint_branch.split("let ep_manuf_raw", 1)[1].split(
437
+ "let ep_manuf =", 1
438
+ )[0]
439
+ self.assertLess(
440
+ chain.index('then "Infoblox"'),
441
+ chain.index("else if hasDescr"),
442
+ filename,
443
+ )
444
+ self.assertLess(
445
+ chain.index('then "Palo Alto Networks"'),
446
+ chain.index("else if hasDescr"),
447
+ filename,
448
+ )
449
+
424
450
  def test_device_query_declares_toggle_default_off(self):
425
451
  for filename in (
426
452
  "forward_devices.nqe",
@@ -398,6 +398,18 @@ class FieldScopedValidationRuleTests(SimpleTestCase):
398
398
  ["untagged-vlan-outside-device-site"], diagnosis["validation_rules"]
399
399
  )
400
400
 
401
+ def test_an_ospf_name_collision_is_named(self):
402
+ # netbox-routing 0.5.0 unique (device, name): reported on a customer sync
403
+ # as an unrecognised rule until this slug existed.
404
+ diagnosis = structured_failure_diagnosis(
405
+ ValidationError(
406
+ "Name must be unique per device Only a single empty name is "
407
+ "permitted per device"
408
+ )
409
+ )
410
+ self.assertEqual(["name-not-unique-per-device"], diagnosis["validation_rules"])
411
+ self.assertNotIn("unrecognized_validation_rules", diagnosis)
412
+
401
413
  def test_untagged_vlan_without_mode_is_named(self):
402
414
  diagnosis = structured_failure_diagnosis(self.UNTAGGED_VLAN_MODE)
403
415
  self.assertEqual(