forward-netbox 3.0.2__tar.gz → 3.0.3__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.3}/PKG-INFO +6 -4
  2. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/README.md +4 -3
  3. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/__init__.py +1 -1
  4. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/templates/forward_netbox/forwardsync_scope_reconciliation.html +5 -1
  5. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_bulk_merge.py +14 -3
  6. forward_netbox-3.0.3/forward_netbox/tests/test_bundle_triage_diagnostics.py +173 -0
  7. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_merge_rule_rejection.py +12 -0
  8. forward_netbox-3.0.3/forward_netbox/tests/test_null_vrf_identity.py +119 -0
  9. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_optional_plugin_versions.py +1 -1
  10. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_ospf_drift_comparison.py +23 -1
  11. forward_netbox-3.0.3/forward_netbox/tests/test_ospf_instance_names.py +27 -0
  12. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_primary_ip.py +25 -0
  13. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_primary_ip_integration.py +43 -0
  14. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_runtime_dependency_check.py +1 -1
  15. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_scope_reconciliation_site_aware.py +56 -4
  16. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_site_relabel_pairs_merge.py +34 -0
  17. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_site_relabel_prompts.py +20 -0
  18. forward_netbox-3.0.3/forward_netbox/tests/test_stale_untagged_vlan_cleared.py +141 -0
  19. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_sync.py +12 -12
  20. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/apply_engine_bulk.py +10 -0
  21. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/bundle_diagnostics.py +29 -0
  22. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/diagnostics.py +8 -0
  23. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/fast_baseline.py +1 -1
  24. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/plugin_integrations/registry.py +22 -2
  25. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/primary_ip.py +75 -6
  26. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/scope_reconciliation.py +60 -19
  27. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/sync_contracts.py +8 -4
  28. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/sync_interface.py +33 -0
  29. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/sync_routing_impl.py +17 -1
  30. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/views.py +159 -1
  31. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/pyproject.toml +8 -2
  32. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/LICENSE +0 -0
  33. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/api/__init__.py +0 -0
  34. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/api/serializers.py +0 -0
  35. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/api/urls.py +0 -0
  36. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/api/views.py +0 -0
  37. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/change_control/__init__.py +0 -0
  38. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/change_control/choices.py +0 -0
  39. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/change_control/criteria.py +0 -0
  40. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/change_control/evidence.py +0 -0
  41. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/change_control/gates.py +0 -0
  42. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/change_control/policy.py +0 -0
  43. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/change_control/predict.py +0 -0
  44. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/change_control/state_machine.py +0 -0
  45. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/choices.py +0 -0
  46. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/exceptions.py +0 -0
  47. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/filtersets.py +0 -0
  48. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/forms.py +0 -0
  49. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/jobs.py +0 -0
  50. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/management/__init__.py +0 -0
  51. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/management/commands/__init__.py +0 -0
  52. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/management/commands/forward_accept_merge_failures.py +0 -0
  53. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/management/commands/forward_apic_cimc_readiness_audit.py +0 -0
  54. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/management/commands/forward_apply_identity_audit.py +0 -0
  55. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/management/commands/forward_blocker_audit.py +0 -0
  56. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/management/commands/forward_changediff_audit.py +0 -0
  57. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/management/commands/forward_collection_gap_alert.py +0 -0
  58. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/management/commands/forward_device_name_ambiguity_audit.py +0 -0
  59. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/management/commands/forward_device_scope_reconciliation_audit.py +0 -0
  60. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/management/commands/forward_dlm_hardware_notice_audit.py +0 -0
  61. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/management/commands/forward_fast_baseline_preflight.py +0 -0
  62. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/management/commands/forward_interface_vlan_audit.py +0 -0
  63. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/management/commands/forward_link_vsys_parents.py +0 -0
  64. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/management/commands/forward_metrics.py +0 -0
  65. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/management/commands/forward_module_readiness.py +0 -0
  66. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/management/commands/forward_ownership_audit.py +0 -0
  67. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/management/commands/forward_primary_ip_audit.py +0 -0
  68. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/management/commands/forward_profile_merge.py +0 -0
  69. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/management/commands/forward_pushdown_profile.py +0 -0
  70. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/management/commands/forward_query_diff_coverage_audit.py +0 -0
  71. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/management/commands/forward_resolve_query_ids.py +0 -0
  72. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/management/commands/forward_routing_dangling_audit.py +0 -0
  73. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/management/commands/forward_scope_ipam_audit.py +0 -0
  74. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/management/commands/forward_seed_ui_harness.py +0 -0
  75. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/management/commands/forward_smoke_sync.py +0 -0
  76. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/management/commands/forward_stuck_job_alert.py +0 -0
  77. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/management/commands/forward_stuck_job_recover.py +0 -0
  78. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/management/commands/forward_tag_delete_eligible.py +0 -0
  79. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/management/commands/forward_validation_org_query_audit.py +0 -0
  80. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/management/commands/forward_warning_audit.py +0 -0
  81. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/management/commands/forward_watch_sync.py +0 -0
  82. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/migrations/0001_initial.py +0 -0
  83. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/migrations/0002_add_coalesce_fields.py +0 -0
  84. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/migrations/0003_forwardingestionissue_context_fields.py +0 -0
  85. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/migrations/0004_forwardingestion_baseline_fields.py +0 -0
  86. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/migrations/0005_validation_and_reporting.py +0 -0
  87. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/migrations/0006_alter_forwardnqemap_netbox_model.py +0 -0
  88. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/migrations/0007_forwardingestion_persisted_change_counters.py +0 -0
  89. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/migrations/0008_alter_forwardnqemap_netbox_model.py +0 -0
  90. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/migrations/0009_alter_forwardnqemap_netbox_model.py +0 -0
  91. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/migrations/0010_forwardvalidationrun_override_applied_and_more.py +0 -0
  92. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/migrations/0011_forwardingestion_change_request_id.py +0 -0
  93. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/migrations/0012_forwardnqemap_query_reference.py +0 -0
  94. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/migrations/0013_execution_run_step.py +0 -0
  95. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/migrations/0014_execution_step_fetch_scope.py +0 -0
  96. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/migrations/0015_execution_step_apply_engine.py +0 -0
  97. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/migrations/0016_execution_step_query_metrics.py +0 -0
  98. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/migrations/0017_execution_step_row_counters.py +0 -0
  99. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/migrations/0018_execution_run_reconciliation_events.py +0 -0
  100. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/migrations/0019_forwardexecutionstep_query_parameters.py +0 -0
  101. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/migrations/0020_execution_step_operation.py +0 -0
  102. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/migrations/0021_add_fhrpgroup_nqe_map_choice.py +0 -0
  103. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/migrations/0022_alter_forwardnqemap_netbox_model.py +0 -0
  104. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/migrations/0023_split_ip_address_maps.py +0 -0
  105. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/migrations/0024_forwarddeviceanalysis.py +0 -0
  106. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/migrations/0025_device_analysis_netboxmodel.py +0 -0
  107. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/migrations/0026_forwarddeviceanalysis_collection_result.py +0 -0
  108. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/migrations/0027_alter_forwardexecutionrun_backend.py +0 -0
  109. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/migrations/0028_remove_forwardexecutionstep_run_and_more.py +0 -0
  110. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/migrations/0029_forward_parent_device_cf.py +0 -0
  111. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/migrations/0030_forwarddeviceanalysis_cve_ids.py +0 -0
  112. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/migrations/0031_encrypt_source_password.py +0 -0
  113. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/migrations/0032_alter_forwardnqemap_netbox_model.py +0 -0
  114. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/migrations/0033_alter_forwardnqemap_netbox_model.py +0 -0
  115. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/migrations/0034_source_ownership_provenance.py +0 -0
  116. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/migrations/0035_initialize_ownership_control_plane.py +0 -0
  117. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/migrations/0036_protect_ownership_provenance.py +0 -0
  118. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/migrations/0037_merge_identity_and_assignment_provenance.py +0 -0
  119. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/migrations/0038_managed_tag_domain_guard.py +0 -0
  120. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/migrations/0039_forwardingestion_catchup_state.py +0 -0
  121. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/migrations/0040_remove_redundant_nqe_settings.py +0 -0
  122. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/migrations/0041_forwardworkloadstate.py +0 -0
  123. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/migrations/0042_device_generic_relation_guards.py +0 -0
  124. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/migrations/0043_forwardnqemap_diff_contract.py +0 -0
  125. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/migrations/0044_contributor_baseline_cache.py +0 -0
  126. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/migrations/0045_forwardmergeattempt.py +0 -0
  127. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/migrations/0046_alter_forwardnqemap_netbox_model.py +0 -0
  128. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/migrations/0047_ownership_reconciliation_cascade.py +0 -0
  129. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/migrations/0048_forwardingestion_skipped_change_count.py +0 -0
  130. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/migrations/0049_drift_policy_row_shrink_floor.py +0 -0
  131. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/migrations/0050_contributor_baseline_cascade.py +0 -0
  132. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/migrations/0051_ownership_provenance_stamp_nullable.py +0 -0
  133. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/migrations/0052_device_absence_quarantine.py +0 -0
  134. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/migrations/0053_alter_forwardsource_owner.py +0 -0
  135. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/migrations/0053_routing_policy_nqe_map_choices.py +0 -0
  136. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/migrations/0054_aci_tenant_policy_nqe_map_choices.py +0 -0
  137. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/migrations/0054_forwardchange_forwardchangecriterion_and_more.py +0 -0
  138. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/migrations/0055_change_control_approvals.py +0 -0
  139. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/migrations/0055_operator_delete_releases_ownership.py +0 -0
  140. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/migrations/0056_aci_attachment_nqe_map_choices.py +0 -0
  141. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/migrations/0056_routing_policy_nqe_map_choices.py +0 -0
  142. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/migrations/0057_aci_tenant_policy_nqe_map_choices.py +0 -0
  143. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/migrations/0057_nqe_map_last_live_drift.py +0 -0
  144. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/migrations/0058_operator_delete_releases_ownership.py +0 -0
  145. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/migrations/0059_aci_attachment_nqe_map_choices.py +0 -0
  146. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/migrations/0060_merge_maint_2_9_x_history.py +0 -0
  147. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/migrations/0061_static_route_nqe_map_choice.py +0 -0
  148. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/migrations/__init__.py +0 -0
  149. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/models.py +0 -0
  150. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/navigation.py +0 -0
  151. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/__init__.py +0 -0
  152. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/forward_aci_apic_cimc_inventory.nqe +0 -0
  153. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/forward_aci_apic_filters.nqe +0 -0
  154. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/forward_aci_apic_nodes.nqe +0 -0
  155. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/forward_aci_apic_pods.nqe +0 -0
  156. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/forward_aci_app_profiles.nqe +0 -0
  157. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/forward_aci_bridge_domains.nqe +0 -0
  158. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/forward_aci_command_inventory.nqe +0 -0
  159. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/forward_aci_contracts.nqe +0 -0
  160. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/forward_aci_endpoint_groups.nqe +0 -0
  161. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/forward_aci_fabrics.nqe +0 -0
  162. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/forward_aci_filter_entries.nqe +0 -0
  163. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/forward_aci_filters.nqe +0 -0
  164. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/forward_aci_l3outs.nqe +0 -0
  165. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/forward_aci_nodes.nqe +0 -0
  166. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/forward_aci_pods.nqe +0 -0
  167. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/forward_aci_source_readiness.nqe +0 -0
  168. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/forward_aci_static_port_bindings.nqe +0 -0
  169. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/forward_aci_subject_filters.nqe +0 -0
  170. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/forward_aci_subjects.nqe +0 -0
  171. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/forward_aci_tenants.nqe +0 -0
  172. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/forward_aci_vrfs.nqe +0 -0
  173. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/forward_bgp_address_families.nqe +0 -0
  174. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/forward_bgp_peer_address_families.nqe +0 -0
  175. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/forward_bgp_peers.nqe +0 -0
  176. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/forward_cimc_endpoint_inventory.nqe +0 -0
  177. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/forward_config_backup.nqe +0 -0
  178. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/forward_device_analysis.nqe +0 -0
  179. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/forward_device_feature_tags.nqe +0 -0
  180. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/forward_device_feature_tags_with_rules.nqe +0 -0
  181. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/forward_device_models.nqe +0 -0
  182. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/forward_device_models_with_netbox_aliases.nqe +0 -0
  183. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/forward_device_types.nqe +0 -0
  184. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/forward_device_vendors.nqe +0 -0
  185. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/forward_devices.nqe +0 -0
  186. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/forward_devices_with_netbox_aliases.nqe +0 -0
  187. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/forward_dlm_apic_cimc_inventory_item_software.nqe +0 -0
  188. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/forward_dlm_cves.nqe +0 -0
  189. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/forward_dlm_device_software.nqe +0 -0
  190. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/forward_dlm_hardware_notices.nqe +0 -0
  191. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/forward_dlm_hardware_notices_with_netbox_aliases.nqe +0 -0
  192. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/forward_dlm_inventory_item_software.nqe +0 -0
  193. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/forward_dlm_software_versions.nqe +0 -0
  194. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/forward_dlm_vulnerabilities.nqe +0 -0
  195. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/forward_hsrp_groups.nqe +0 -0
  196. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/forward_inferred_interface_cables.nqe +0 -0
  197. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/forward_interfaces.nqe +0 -0
  198. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/forward_inventory_items.nqe +0 -0
  199. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/forward_ip_addresses_ipv4.nqe +0 -0
  200. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/forward_ip_addresses_ipv6.nqe +0 -0
  201. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/forward_ip_addresses_unassignable_diagnostics.nqe +0 -0
  202. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/forward_locations.nqe +0 -0
  203. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/forward_mac_addresses.nqe +0 -0
  204. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/forward_modules.nqe +0 -0
  205. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/forward_ospf_areas.nqe +0 -0
  206. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/forward_ospf_instances.nqe +0 -0
  207. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/forward_ospf_interfaces.nqe +0 -0
  208. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/forward_peering_sessions.nqe +0 -0
  209. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/forward_platforms.nqe +0 -0
  210. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/forward_prefixes_ipv4.nqe +0 -0
  211. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/forward_prefixes_ipv6.nqe +0 -0
  212. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/forward_routing_community_lists.nqe +0 -0
  213. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/forward_routing_import_diagnostics.nqe +0 -0
  214. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/forward_routing_prefix_lists.nqe +0 -0
  215. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/forward_routing_route_maps.nqe +0 -0
  216. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/forward_static_routes.nqe +0 -0
  217. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/forward_virtual_chassis.nqe +0 -0
  218. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/forward_vlans.nqe +0 -0
  219. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/forward_vrfs.nqe +0 -0
  220. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/queries/netbox_utilities.nqe +0 -0
  221. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/signals.py +0 -0
  222. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/static/forward_netbox/img/fn-logo.svg +0 -0
  223. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tables.py +0 -0
  224. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/template_content.py +0 -0
  225. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/templates/forward_netbox/device_cves.html +0 -0
  226. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/templates/forward_netbox/forwardchange.html +0 -0
  227. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/templates/forward_netbox/forwardchangepolicy.html +0 -0
  228. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/templates/forward_netbox/forwarddeviceanalysis.html +0 -0
  229. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/templates/forward_netbox/forwarddriftpolicy.html +0 -0
  230. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/templates/forward_netbox/forwardingestion.html +0 -0
  231. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/templates/forward_netbox/forwardingestionissue.html +0 -0
  232. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/templates/forward_netbox/forwardnqemap.html +0 -0
  233. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/templates/forward_netbox/forwardsource.html +0 -0
  234. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/templates/forward_netbox/forwardsync.html +0 -0
  235. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/templates/forward_netbox/forwardsync_audit_report.html +0 -0
  236. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/templates/forward_netbox/forwardsync_audits.html +0 -0
  237. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/templates/forward_netbox/forwardsync_delete.html +0 -0
  238. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/templates/forward_netbox/forwardsync_dependency_preview.html +0 -0
  239. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/templates/forward_netbox/forwardsync_drift_report.html +0 -0
  240. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/templates/forward_netbox/forwardsync_health.html +0 -0
  241. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/templates/forward_netbox/forwardsync_module_readiness.html +0 -0
  242. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/templates/forward_netbox/forwardsync_uncovered_devices.html +0 -0
  243. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/templates/forward_netbox/forwardvalidationrun.html +0 -0
  244. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/templates/forward_netbox/htmx/forwardsync_delete_form.html +0 -0
  245. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/templates/forward_netbox/inc/brand_bar.html +0 -0
  246. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/templates/forward_netbox/inc/count_trend.html +0 -0
  247. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/templates/forward_netbox/inc/device_analysis_panel.html +0 -0
  248. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/templates/forward_netbox/inc/device_ownership_panel.html +0 -0
  249. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/templates/forward_netbox/inc/diff.html +0 -0
  250. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/templates/forward_netbox/inc/execution_insights.html +0 -0
  251. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/templates/forward_netbox/inc/logs_pending.html +0 -0
  252. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/templates/forward_netbox/inc/merge_form.html +0 -0
  253. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/templates/forward_netbox/inc/validation_force_allow_form.html +0 -0
  254. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/templates/forward_netbox/partials/change_explainability.html +0 -0
  255. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/templates/forward_netbox/partials/ingestion_all.html +0 -0
  256. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/templates/forward_netbox/partials/ingestion_merge_button.html +0 -0
  257. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/templates/forward_netbox/partials/ingestion_progress.html +0 -0
  258. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/templates/forward_netbox/partials/ingestion_statistics.html +0 -0
  259. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/templates/forward_netbox/partials/ingestion_status.html +0 -0
  260. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/templates/forward_netbox/partials/job_logs.html +0 -0
  261. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/templates/forward_netbox/partials/object_tabs.html +0 -0
  262. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/templates/forward_netbox/partials/stage_switcher_buttons.html +0 -0
  263. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/templates/forward_netbox/partials/validation_force_allow_button.html +0 -0
  264. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/templatetags/__init__.py +0 -0
  265. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/templatetags/forward_netbox_helpers.py +0 -0
  266. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/__init__.py +0 -0
  267. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/fixtures/aci_command_inventory_expected.json +0 -0
  268. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/fixtures/aci_discovery_expected.json +0 -0
  269. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_a_warning_is_not_a_failure.py +0 -0
  270. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_absence_quarantine.py +0 -0
  271. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_absent_configuration_detail.py +0 -0
  272. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_absent_device_does_not_block_tag_domain.py +0 -0
  273. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_accepted_merge_failures.py +0 -0
  274. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_aci_drift_comparison.py +0 -0
  275. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_aci_source_readiness.py +0 -0
  276. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_adapter_drift_scale.py +0 -0
  277. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_api_serializer_base.py +0 -0
  278. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_api_usage.py +0 -0
  279. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_api_views.py +0 -0
  280. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_apic_cimc_readiness_audit_command.py +0 -0
  281. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_apply_engine.py +0 -0
  282. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_apply_identity_audit.py +0 -0
  283. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_audit_report_views.py +0 -0
  284. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_bgp_peer_af_query.py +0 -0
  285. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_bgp_peer_comment_churn.py +0 -0
  286. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_bgp_peer_policy_links.py +0 -0
  287. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_bgp_peer_round_trip_variants.py +0 -0
  288. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_branch_budget_split.py +0 -0
  289. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_branching.py +0 -0
  290. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_brand_bar.py +0 -0
  291. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_builtin_query_id_binding.py +0 -0
  292. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_bulk_adapter_parity.py +0 -0
  293. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_bulk_merge_scale.py +0 -0
  294. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_bundle_diagnostics_parity.py +0 -0
  295. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_button_jobs.py +0 -0
  296. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_cable_drift_comparison.py +0 -0
  297. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_catalogue_models_compare.py +0 -0
  298. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_change_control_evidence.py +0 -0
  299. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_change_control_gates.py +0 -0
  300. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_change_control_policy.py +0 -0
  301. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_change_control_predict.py +0 -0
  302. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_change_control_state_machine.py +0 -0
  303. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_change_explainability_full_counts.py +0 -0
  304. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_changediff_audit.py +0 -0
  305. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_collection_collapse_guard.py +0 -0
  306. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_config_backup.py +0 -0
  307. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_config_backup_folder.py +0 -0
  308. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_config_backup_job_and_health.py +0 -0
  309. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_config_backup_path.py +0 -0
  310. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_config_backup_query.py +0 -0
  311. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_config_backup_result_evidence.py +0 -0
  312. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_constraint_diagnosis.py +0 -0
  313. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_contract_preflight_message.py +0 -0
  314. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_contributor_baseline.py +0 -0
  315. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_converged_models_are_measured.py +0 -0
  316. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_copy_sql_apply_engine.py +0 -0
  317. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_cross_site_vlan_revalidation.py +0 -0
  318. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_crypto.py +0 -0
  319. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_density_observation.py +0 -0
  320. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_dependency_preview_summary.py +0 -0
  321. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_device_analysis_query.py +0 -0
  322. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_device_name_case_identity.py +0 -0
  323. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_device_scope_reconciliation_audit_command.py +0 -0
  324. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_device_scope_tagging.py +0 -0
  325. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_device_site_relabel_identity.py +0 -0
  326. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_diagnostics_readback.py +0 -0
  327. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_diff_removal_allowlist.py +0 -0
  328. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_dlm_catalogue_conflicts.py +0 -0
  329. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_dlm_drift_comparison.py +0 -0
  330. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_dlm_hardware_notice_audit.py +0 -0
  331. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_dlm_integration.py +0 -0
  332. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_dlm_inventoryitem_drift_comparison.py +0 -0
  333. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_drift_comparison.py +0 -0
  334. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_drift_coverage_is_explained.py +0 -0
  335. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_drift_rows_are_distinguishable.py +0 -0
  336. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_durable_workload_state_attribution.py +0 -0
  337. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_empty_comparison_is_not_a_measurement.py +0 -0
  338. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_empty_workload_failure.py +0 -0
  339. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_endpoint_absence_detail.py +0 -0
  340. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_endpoint_ipv4_netmask.py +0 -0
  341. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_endpoints_import.py +0 -0
  342. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_execute_by_query_id_without_commit.py +0 -0
  343. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_execution_insights_delete_label.py +0 -0
  344. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_export_redaction.py +0 -0
  345. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_failed_run_model_evidence.py +0 -0
  346. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_fast_baseline.py +0 -0
  347. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_fast_paths_report_when_disabled.py +0 -0
  348. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_fast_paths_subset_runtime.py +0 -0
  349. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_fhrpgroup_drift_comparison.py +0 -0
  350. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_field_reported_integrity_failures.py +0 -0
  351. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_force_allow_override.py +0 -0
  352. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_forms.py +0 -0
  353. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_forward_api.py +0 -0
  354. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_forward_client_errors.py +0 -0
  355. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_forward_client_factory.py +0 -0
  356. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_forward_usage_hooks.py +0 -0
  357. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_full_removal_reconciliation.py +0 -0
  358. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_head_commit_from_listing.py +0 -0
  359. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_health.py +0 -0
  360. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_health_evidence.py +0 -0
  361. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_ingestion_delete.py +0 -0
  362. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_ingestion_is_deletable.py +0 -0
  363. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_ingestion_merge.py +0 -0
  364. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_interface_lookup_query_shape.py +0 -0
  365. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_interface_naming.py +0 -0
  366. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_interface_vlan_audit.py +0 -0
  367. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_inventoryitem_drift_comparison.py +0 -0
  368. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_ip_address_dedup_query.py +0 -0
  369. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_ipaddress_dup_global.py +0 -0
  370. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_issue_diagnosis.py +0 -0
  371. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_issue_rendering.py +0 -0
  372. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_job_liveness.py +0 -0
  373. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_job_queue.py +0 -0
  374. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_jobs.py +0 -0
  375. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_keyerror_names_its_key.py +0 -0
  376. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_license_tier.py +0 -0
  377. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_log_export.py +0 -0
  378. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_logging.py +0 -0
  379. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_merge_observability.py +0 -0
  380. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_merge_profiling.py +0 -0
  381. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_migration_dependencies.py +0 -0
  382. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_migration_lineage.py +0 -0
  383. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_migrations.py +0 -0
  384. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_mixed_model_change_diffs.py +0 -0
  385. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_model_view_routes.py +0 -0
  386. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_models.py +0 -0
  387. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_module_drift_comparison.py +0 -0
  388. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_module_readiness.py +0 -0
  389. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_module_readiness_rollup.py +0 -0
  390. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_nqe_lint_blind_spots.py +0 -0
  391. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_operator_commands.py +0 -0
  392. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_operator_delete_releases_ownership.py +0 -0
  393. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_ospf_neighbour_rows_converge.py +0 -0
  394. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_ownership.py +0 -0
  395. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_ownership_command.py +0 -0
  396. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_ownership_completes_with_preexisting_status_tag.py +0 -0
  397. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_ownership_conflict_reason.py +0 -0
  398. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_ownership_lock_wait.py +0 -0
  399. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_ownership_migration.py +0 -0
  400. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_parameter_signature_drift.py +0 -0
  401. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_peering_drift_comparison.py +0 -0
  402. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_plan_statistics_monotonic.py +0 -0
  403. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_plugin_integrations.py +0 -0
  404. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_post_sync.py +0 -0
  405. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_preview_isolation.py +0 -0
  406. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_preview_primes_its_lookup_caches.py +0 -0
  407. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_preview_reports_its_cost.py +0 -0
  408. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_preview_runner_satisfies_the_priming_contract.py +0 -0
  409. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_primary_ip_audit.py +0 -0
  410. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_primary_ip_duplicate_names.py +0 -0
  411. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_protected_delete_is_a_skip.py +0 -0
  412. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_protecting_reference_deletes.py +0 -0
  413. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_protecting_relations.py +0 -0
  414. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_provision_preflight.py +0 -0
  415. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_quarantine_cadence.py +0 -0
  416. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_query_binding.py +0 -0
  417. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_query_diff_coverage_audit_command.py +0 -0
  418. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_query_execution_contract.py +0 -0
  419. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_query_id_binding_end_to_end.py +0 -0
  420. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_query_registry.py +0 -0
  421. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_query_signature_drift_check.py +0 -0
  422. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_query_variants.py +0 -0
  423. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_raise_site_is_recorded.py +0 -0
  424. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_refused_deletes_are_not_staged.py +0 -0
  425. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_refused_deletes_are_retried.py +0 -0
  426. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_release_foreign_delete_blockers.py +0 -0
  427. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_release_readiness_audit.py +0 -0
  428. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_reserved_status_tag_adoption.py +0 -0
  429. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_routing_apply_compare_round_trip.py +0 -0
  430. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_routing_catalogue_cleanup.py +0 -0
  431. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_routing_catalogue_drift.py +0 -0
  432. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_routing_catalogue_scope.py +0 -0
  433. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_row_collapsing.py +0 -0
  434. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_row_count_floor.py +0 -0
  435. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_run_size_anomaly.py +0 -0
  436. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_run_size_guard.py +0 -0
  437. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_scheduled_jobs.py +0 -0
  438. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_scope_audit_full.py +0 -0
  439. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_scope_ipam_audit.py +0 -0
  440. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_scope_matched_tags.py +0 -0
  441. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_scope_module_ui.py +0 -0
  442. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_scope_reconciliation_view.py +0 -0
  443. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_scope_shrink_guard.py +0 -0
  444. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_scope_tag_slug_collision.py +0 -0
  445. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_sdk_result_contract.py +0 -0
  446. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_set_based_merge.py +0 -0
  447. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_skip_dependency_direction.py +0 -0
  448. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_skip_names_netbox_row.py +0 -0
  449. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_skip_raisers_name_dependency.py +0 -0
  450. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_skip_rollup_direction.py +0 -0
  451. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_smoke_sync_command.py +0 -0
  452. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_source_parameter_keys_agree.py +0 -0
  453. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_stability_hardening.py +0 -0
  454. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_static_routes_query.py +0 -0
  455. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_stuck_recovery.py +0 -0
  456. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_support_bundle_archive.py +0 -0
  457. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_sync_aci.py +0 -0
  458. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_sync_facade.py +0 -0
  459. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_sync_orchestration.py +0 -0
  460. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_sync_recurrence_pinning.py +0 -0
  461. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_sync_routing_policy.py +0 -0
  462. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_sync_routing_static.py +0 -0
  463. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_sync_runner_contracts.py +0 -0
  464. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_sync_state.py +0 -0
  465. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_taggeditem_drift_comparison.py +0 -0
  466. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_tier3_reducers.py +0 -0
  467. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_tree_model_detection.py +0 -0
  468. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_uncovered_absence_and_trend.py +0 -0
  469. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_uncovered_device_cleanup.py +0 -0
  470. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_uncovered_device_tag.py +0 -0
  471. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_upgrade_reconciliation.py +0 -0
  472. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_validated_runtime_is_declared_once.py +0 -0
  473. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_validation_org_query_audit_command.py +0 -0
  474. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_virtualchassis_drift_comparison.py +0 -0
  475. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_vsys_parent.py +0 -0
  476. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_workload_normalization.py +0 -0
  477. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/tests/test_workload_state.py +0 -0
  478. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/urls.py +0 -0
  479. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/__init__.py +0 -0
  480. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/api_usage.py +0 -0
  481. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/apic_cimc_readiness.py +0 -0
  482. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/apply_engine.py +0 -0
  483. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/apply_engine_copy_sql.py +0 -0
  484. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/apply_engine_decision.py +0 -0
  485. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/apply_identity_audit.py +0 -0
  486. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/audit_reports.py +0 -0
  487. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/branch_budget.py +0 -0
  488. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/branch_lifecycle.py +0 -0
  489. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/branching.py +0 -0
  490. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/bulk_delete.py +0 -0
  491. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/bulk_merge.py +0 -0
  492. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/change_explainability.py +0 -0
  493. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/changediff_audit.py +0 -0
  494. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/config_backup.py +0 -0
  495. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/config_backup_path.py +0 -0
  496. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/constraint_diagnosis.py +0 -0
  497. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/contributor_baseline.py +0 -0
  498. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/crypto.py +0 -0
  499. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/delete_policy.py +0 -0
  500. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/density_learning.py +0 -0
  501. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/device_analysis.py +0 -0
  502. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/direct_changes.py +0 -0
  503. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/dlm_notice_audit.py +0 -0
  504. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/drift_comparison.py +0 -0
  505. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/drift_report.py +0 -0
  506. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/execution_telemetry.py +0 -0
  507. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/executor_base.py +0 -0
  508. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/export_redaction.py +0 -0
  509. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/fast_baseline_models.py +0 -0
  510. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/forward_api.py +0 -0
  511. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/forward_api_impl.py +0 -0
  512. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/forward_client_config.py +0 -0
  513. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/forward_client_errors.py +0 -0
  514. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/forward_client_factory.py +0 -0
  515. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/forward_read_cache.py +0 -0
  516. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/forward_throttle.py +0 -0
  517. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/forward_usage.py +0 -0
  518. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/forward_usage_hooks.py +0 -0
  519. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/full_removal_reconciliation.py +0 -0
  520. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/health.py +0 -0
  521. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/health_apply_fetch.py +0 -0
  522. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/health_checks.py +0 -0
  523. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/health_evidence.py +0 -0
  524. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/health_summary_blocks.py +0 -0
  525. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/ingestion_issues.py +0 -0
  526. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/ingestion_merge.py +0 -0
  527. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/ingestion_presentation.py +0 -0
  528. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/interface_naming.py +0 -0
  529. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/interface_vlan_audit.py +0 -0
  530. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/job_liveness.py +0 -0
  531. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/job_queue.py +0 -0
  532. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/json_safe.py +0 -0
  533. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/license_tier.py +0 -0
  534. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/logging.py +0 -0
  535. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/merge.py +0 -0
  536. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/merge_observability.py +0 -0
  537. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/merge_profiling.py +0 -0
  538. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/merge_set_based.py +0 -0
  539. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/model_contracts.py +0 -0
  540. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/model_validation.py +0 -0
  541. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/module_readiness.py +0 -0
  542. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/ownership.py +0 -0
  543. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/plugin_integrations/__init__.py +0 -0
  544. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/post_sync.py +0 -0
  545. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/primary_ip_audit.py +0 -0
  546. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/query_binding.py +0 -0
  547. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/query_binding_resolution.py +0 -0
  548. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/query_diagnostics.py +0 -0
  549. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/query_execution_contract.py +0 -0
  550. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/query_fetch.py +0 -0
  551. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/query_fetch_execution.py +0 -0
  552. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/query_registry.py +0 -0
  553. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/routing_catalogue_cleanup.py +0 -0
  554. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/routing_dangling_audit.py +0 -0
  555. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/row_collapsing.py +0 -0
  556. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/run_size_anomaly.py +0 -0
  557. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/run_size_guard.py +0 -0
  558. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/runtime_guidance.py +0 -0
  559. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/scope_ipam_audit.py +0 -0
  560. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/single_branch_executor.py +0 -0
  561. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/snapshot_freshness.py +0 -0
  562. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/stuck_recovery.py +0 -0
  563. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/support_bundle_archive.py +0 -0
  564. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/sync.py +0 -0
  565. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/sync_aci.py +0 -0
  566. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/sync_cable.py +0 -0
  567. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/sync_core_models.py +0 -0
  568. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/sync_device.py +0 -0
  569. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/sync_dlm.py +0 -0
  570. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/sync_events.py +0 -0
  571. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/sync_execution.py +0 -0
  572. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/sync_facade.py +0 -0
  573. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/sync_inventory_module.py +0 -0
  574. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/sync_ipam.py +0 -0
  575. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/sync_orchestration.py +0 -0
  576. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/sync_primitives.py +0 -0
  577. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/sync_reporting.py +0 -0
  578. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/sync_routing.py +0 -0
  579. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/sync_routing_policy.py +0 -0
  580. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/sync_routing_static.py +0 -0
  581. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/sync_runner_adapters.py +0 -0
  582. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/sync_runner_contracts.py +0 -0
  583. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/sync_state.py +0 -0
  584. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/tag_contracts.py +0 -0
  585. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/tier3_reducers.py +0 -0
  586. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/upgrade_reconciliation.py +0 -0
  587. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/validated_runtime.py +0 -0
  588. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/validation.py +0 -0
  589. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/validation_org_query.py +0 -0
  590. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/version_series.py +0 -0
  591. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/vsys_parent.py +0 -0
  592. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/forward_netbox/utilities/workload_normalization.py +0 -0
  593. {forward_netbox-3.0.2 → forward_netbox-3.0.3}/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.3
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,16 @@ 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.3` 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.3` | NetBox `4.7.x` supported, tested on `4.7.1`; needs netbox-branching `1.2.x`, tested on `1.2.0` | Release candidate; 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 |
121
+ | `v3.0.2` | NetBox `4.7.x` supported, tested on `4.7.1`; needs netbox-branching `1.2.x`, tested on `1.2.0` | Current release; Port of 2.9.13's PeeringSession crash + endpoint /32 fixes, plus the 3.0.1 upgrade-runtime override fix |
122
+ | `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
123
  | `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
124
  | `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
125
  | `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,16 @@ 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.3` 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.3` | NetBox `4.7.x` supported, tested on `4.7.1`; needs netbox-branching `1.2.x`, tested on `1.2.0` | Release candidate; 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 |
75
+ | `v3.0.2` | NetBox `4.7.x` supported, tested on `4.7.1`; needs netbox-branching `1.2.x`, tested on `1.2.0` | Current release; Port of 2.9.13's PeeringSession crash + endpoint /32 fixes, plus the 3.0.1 upgrade-runtime override fix |
76
+ | `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
77
  | `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
78
  | `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
79
  | `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.3"
9
9
  base_url = "forward"
10
10
  min_version = "4.7.0"
11
11
  max_version = "4.7.99"
@@ -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 %}
@@ -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,173 @@
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_issues_are_tallied_by_model_exception_and_rule_over_every_row(self):
99
+ ingestion = ForwardIngestion.objects.create(sync=self.sync)
100
+ for _ in range(3):
101
+ ForwardIngestionIssue.objects.create(
102
+ ingestion=ingestion,
103
+ model="dcim.interface",
104
+ exception="ValidationError",
105
+ message="Merge failed",
106
+ raw_data={"validation_rules": ["untagged-vlan-outside-device-site"]},
107
+ )
108
+ ForwardIngestionIssue.objects.create(
109
+ ingestion=ingestion,
110
+ model="dcim.site",
111
+ exception="ForwardDependencySkipError",
112
+ message="skipped",
113
+ raw_data={},
114
+ )
115
+
116
+ summary = _ingestion_issue_bundle_payload(ingestion)["summary"]
117
+
118
+ self.assertEqual(summary["counted"], 4)
119
+ self.assertEqual(
120
+ summary["by_model_and_exception"][0],
121
+ {"model": "dcim.interface", "exception": "ValidationError", "count": 3},
122
+ )
123
+ self.assertEqual(
124
+ summary["by_validation_rule"],
125
+ [
126
+ {
127
+ "model": "dcim.interface",
128
+ "rule": "untagged-vlan-outside-device-site",
129
+ "count": 3,
130
+ }
131
+ ],
132
+ )
133
+
134
+ def test_the_environment_names_the_dependency_versions(self):
135
+ deps = _environment_bundle_payload()["dependency_versions"]
136
+
137
+ for name in ("scrapli", "scrapli-netconf", "forward-sdk", "django"):
138
+ self.assertIn(name, deps)
139
+ # A package that is not installed reads None, never an error.
140
+ self.assertTrue(all(v is None or isinstance(v, str) for v in deps.values()))
141
+ self.assertTrue(deps["django"])
142
+
143
+ def test_a_missing_scope_report_has_no_age_rather_than_a_wrong_one(self):
144
+ payload = _scope_reconciliation_bundle_payload(self.sync)
145
+
146
+ self.assertIsNone(payload["generated_at"])
147
+ self.assertIsNone(payload["age_hours"])
148
+ self.assertIsNone(payload["older_than_last_sync"])
149
+
150
+ def test_routing_name_collisions_reports_whether_the_plugin_is_there(self):
151
+ out = bundle_diagnostics(self.sync)
152
+
153
+ self.assertEqual(out["errors"], {})
154
+ collisions = out["routing_name_collisions"]
155
+ self.assertIn("installed", collisions)
156
+ if collisions["installed"]:
157
+ self.assertEqual(collisions["duplicate_name_groups"], 0)
158
+
159
+ def test_the_new_figures_export_without_names(self):
160
+ self._device("customer-firewall-01", tag="forward-uncovered")
161
+ text = json.dumps(
162
+ export_safe_payload(
163
+ {
164
+ "primary_ip": _primary_ip_bundle_payload(self.sync),
165
+ "diagnostics": bundle_diagnostics(self.sync),
166
+ "environment": _environment_bundle_payload(),
167
+ }
168
+ ),
169
+ default=str,
170
+ )
171
+
172
+ self.assertNotIn("customer-firewall-01", text)
173
+ self.assertNotIn("Secret Street", text)
@@ -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(
@@ -0,0 +1,119 @@
1
+ from unittest import TestCase
2
+
3
+ from forward_netbox.exceptions import ForwardQueryError
4
+ from forward_netbox.utilities.sync_contracts import MODEL_SYNC_CONTRACTS
5
+ from forward_netbox.utilities.sync_contracts import row_coalesce_field_is_complete
6
+ from forward_netbox.utilities.sync_contracts import validate_row_shape_for_model
7
+
8
+ # Models whose bundled query emits a null `vrf` for the global routing table
9
+ # (`vrf: ... else null`) or for a route outside any VRF. Their default coalesce
10
+ # set names `vrf`, so a null `vrf` must still identify the row: a global route
11
+ # is a real, ordinary row, not an incomplete one.
12
+ GLOBAL_TABLE_MODELS = (
13
+ "netbox_routing.staticroute",
14
+ "netbox_routing.bgppeer",
15
+ "netbox_routing.bgpaddressfamily",
16
+ "netbox_routing.bgppeeraddressfamily",
17
+ "netbox_routing.ospfinstance",
18
+ "netbox_peering_manager.peeringsession",
19
+ )
20
+
21
+
22
+ def _identity_row(model_string):
23
+ contract = MODEL_SYNC_CONTRACTS[model_string]
24
+ row = {field: "x" for field in contract.required_fields}
25
+ for field_set in contract.default_coalesce_fields:
26
+ for field in field_set:
27
+ row[field] = "x"
28
+ row["vrf"] = None
29
+ return row
30
+
31
+
32
+ class NullVrfIdentityTest(TestCase):
33
+ def test_a_global_row_satisfies_the_default_coalesce_set(self):
34
+ for model_string in GLOBAL_TABLE_MODELS:
35
+ with self.subTest(model=model_string):
36
+ contract = MODEL_SYNC_CONTRACTS[model_string]
37
+ sets = [list(s) for s in contract.default_coalesce_fields]
38
+ try:
39
+ validate_row_shape_for_model(
40
+ model_string, _identity_row(model_string), sets
41
+ )
42
+ except ForwardQueryError as exc:
43
+ self.fail(f"{model_string} rejects a global-table row: {exc}")
44
+
45
+ def test_the_static_route_row_shape_the_bundled_query_emits_is_accepted(self):
46
+ validate_row_shape_for_model(
47
+ "netbox_routing.staticroute",
48
+ {
49
+ "device": "sw-a",
50
+ "os": "OS.NXOS",
51
+ "vrf": None,
52
+ "family": "ip",
53
+ "args": "0.0.0.0/0 10.0.0.1",
54
+ },
55
+ [["device", "vrf", "family", "args"]],
56
+ )
57
+
58
+ def test_a_missing_vrf_key_is_still_rejected(self):
59
+ row = _identity_row("netbox_routing.staticroute")
60
+ del row["vrf"]
61
+ with self.assertRaises(ForwardQueryError):
62
+ validate_row_shape_for_model(
63
+ "netbox_routing.staticroute",
64
+ row,
65
+ [["device", "vrf", "family", "args"]],
66
+ )
67
+
68
+ def test_other_identity_fields_stay_required(self):
69
+ for field in ("device", "family", "args"):
70
+ with self.subTest(field=field):
71
+ row = _identity_row("netbox_routing.staticroute")
72
+ row[field] = None
73
+ with self.assertRaises(ForwardQueryError):
74
+ validate_row_shape_for_model(
75
+ "netbox_routing.staticroute",
76
+ row,
77
+ [["device", "vrf", "family", "args"]],
78
+ )
79
+
80
+ def test_a_null_vrf_is_complete_only_for_models_that_have_a_global_table(self):
81
+ self.assertFalse(
82
+ row_coalesce_field_is_complete("dcim.device", {"vrf": None}, "vrf")
83
+ )
84
+ self.assertTrue(
85
+ row_coalesce_field_is_complete(
86
+ "netbox_routing.staticroute", {"vrf": None}, "vrf"
87
+ )
88
+ )
89
+
90
+
91
+ class RowShapeFailureIsNamedTest(TestCase):
92
+ def test_a_row_shape_refusal_is_named_not_unrecognized(self):
93
+ from forward_netbox.utilities.diagnostics import failure_reason
94
+
95
+ identity = ForwardQueryError(
96
+ "Row for `netbox_routing.staticroute` does not satisfy any configured "
97
+ "coalesce field set."
98
+ )
99
+ required = ForwardQueryError(
100
+ "Row for `netbox_routing.staticroute` is missing required fields: args."
101
+ )
102
+ self.assertEqual(failure_reason(identity), "row-identity-incomplete")
103
+ self.assertIn("shape-error", failure_reason(required))
104
+
105
+
106
+ class RoutingAdapterReadinessTest(TestCase):
107
+ def test_every_routing_model_reports_its_adapters_present(self):
108
+ from forward_netbox.utilities.plugin_integrations.registry import (
109
+ integration_adapter_contract_summary,
110
+ )
111
+
112
+ summary = integration_adapter_contract_summary()
113
+ routing = next(
114
+ value for key, value in summary.items() if key.startswith("routing")
115
+ )
116
+ self.assertEqual(routing["gaps"], [], routing["gaps"])
117
+ models = {entry["model"] for entry in routing["models"]}
118
+ self.assertIn("netbox_routing.staticroute", models)
119
+ self.assertIn("netbox_routing.routemapentry", models)
@@ -136,7 +136,7 @@ class FastBaselineRuntimeTupleTest(SimpleTestCase):
136
136
 
137
137
  tuple_ = {
138
138
  "netbox": netbox,
139
- "branching": "1.2.0",
139
+ "branching": "1.2.1",
140
140
  "forward_netbox": fast_baseline.forward_config.version,
141
141
  "optional_plugins": (
142
142
  {
@@ -77,10 +77,11 @@ class OspfPreviewTest(TestCase):
77
77
 
78
78
  def _existing_instance(self, *, router_id="10.0.0.1", vrf=None):
79
79
  from forward_netbox.utilities.sync_routing_impl import ospf_instance_comments
80
+ from forward_netbox.utilities.sync_routing_impl import ospf_instance_name
80
81
 
81
82
  OSPFInstance, _, _ = _ospf_models()
82
83
  return OSPFInstance.objects.create(
83
- name=f"{self.device.name} OSPF 1",
84
+ name=ospf_instance_name(self.device.name, "1", vrf.name if vrf else None),
84
85
  router_id=router_id,
85
86
  process_id=1,
86
87
  device=self.device,
@@ -239,6 +240,27 @@ class OspfPreviewTest(TestCase):
239
240
  result = compare_model_rows(None, INSTANCE, [self._row(vrf="TENANT-B")])
240
241
  self.assertEqual(result["unchanged"], 1)
241
242
 
243
+ def test_a_vrf_instance_with_the_old_unsuffixed_name_is_renamed_not_created(self):
244
+ # Instances written before the name carried the VRF are matched on
245
+ # (device, vrf, process_id), so the sync renames them in place.
246
+ from forward_netbox.utilities.sync_routing_impl import ospf_instance_comments
247
+
248
+ OSPFInstance, _, _ = _ospf_models()
249
+ vrf = VRF.objects.create(name="TENANT-C")
250
+ OSPFInstance.objects.create(
251
+ name=f"{self.device.name} OSPF 1",
252
+ router_id="10.0.0.1",
253
+ process_id=1,
254
+ device=self.device,
255
+ vrf=vrf,
256
+ comments=ospf_instance_comments(self._row(), "1"),
257
+ )
258
+
259
+ result = compare_model_rows(None, INSTANCE, [self._row(vrf="TENANT-C")])
260
+
261
+ self.assertEqual(result["creates"], 0)
262
+ self.assertEqual(result["unchanged"], 0)
263
+
242
264
  # --- rows the apply refuses -------------------------------------------
243
265
 
244
266
  def test_an_instance_without_a_router_id_is_rejected(self):
@@ -0,0 +1,27 @@
1
+ from unittest import TestCase
2
+
3
+ from forward_netbox.utilities.sync_routing_impl import ospf_instance_name
4
+
5
+
6
+ class OspfInstanceNameTest(TestCase):
7
+ def test_the_global_table_keeps_the_name_it_always_had(self):
8
+ self.assertEqual(
9
+ ospf_instance_name("sw-a", "default", None), "sw-a OSPF default"
10
+ )
11
+ self.assertEqual(ospf_instance_name("sw-a", "1", ""), "sw-a OSPF 1")
12
+
13
+ def test_the_same_process_in_two_vrfs_gets_two_names(self):
14
+ # netbox-routing 0.5.0 enforces unique (device, name) on OSPF instances.
15
+ names = {
16
+ ospf_instance_name("sw-a", "default", None),
17
+ ospf_instance_name("sw-a", "default", "BLUE"),
18
+ ospf_instance_name("sw-a", "default", "RED"),
19
+ }
20
+ self.assertEqual(len(names), 3)
21
+
22
+ def test_a_long_name_is_cut_in_the_base_never_in_the_vrf(self):
23
+ name = ospf_instance_name("d" * 120, "default", "BLUE")
24
+ self.assertEqual(len(name), 100)
25
+ self.assertTrue(name.endswith(" (BLUE)"))
26
+ other = ospf_instance_name("d" * 120, "default", "RED")
27
+ self.assertNotEqual(name, other)
@@ -152,6 +152,31 @@ class ResolveManagementIpAssignmentsTest(SimpleTestCase):
152
152
 
153
153
  self.assertEqual(result, {})
154
154
 
155
+ def test_unresolved_devices_report_why(self):
156
+ reasons = {}
157
+ self._resolve(
158
+ {
159
+ "many": ["10.0.0.1", "10.0.0.2"],
160
+ "none": ["10.0.0.3"],
161
+ "two": ["10.0.0.4"],
162
+ },
163
+ {
164
+ "many": {"Lo0": ["10.0.0.1/32"]},
165
+ "none": {"Lo0": ["10.9.9.9/32"]},
166
+ "two": {"Lo0": ["10.0.0.4/32"], "Vlan1": ["10.0.0.4/24"]},
167
+ },
168
+ reasons=reasons,
169
+ )
170
+
171
+ self.assertEqual(
172
+ reasons,
173
+ {
174
+ "many": "multiple-addresses",
175
+ "none": "no-interface",
176
+ "two": "several-interfaces",
177
+ },
178
+ )
179
+
155
180
  def test_a_device_with_a_mgmt_tag_is_never_given_the_fallback(self):
156
181
  result = self._resolve(
157
182
  {"r1": ["10.0.0.1"]},
@@ -214,6 +214,49 @@ class PrimaryIpFromMgmtTagIntegrationTest(TransactionTestCase):
214
214
 
215
215
  executor.get_device_management_ips.assert_not_called()
216
216
 
217
+ def test_a_tag_that_resolves_nothing_still_gets_the_management_address(self):
218
+ # `Mgmt_Nope` names no interface, so the tag leaves the device bare. It
219
+ # used to block the fallback too, which left 590 tagged devices on one
220
+ # estate without a primary IP even though their management address sat
221
+ # on an interface.
222
+ self._enable(tag=True, fallback=True)
223
+ branch = provision_branch(user=self.user, name="Unresolved Tag Branch")
224
+ executor = self._fallback_executor(
225
+ mgmt_tags={"r1": ["Mgmt_Nope9"]},
226
+ management_ips={"r1": ["10.0.211.2"]},
227
+ )
228
+
229
+ updated = apply_primary_ip_from_mgmt_tags(
230
+ executor, branch, snapshot_id="snap-1"
231
+ )
232
+
233
+ self.assertEqual(updated, 1)
234
+ with activate_branch(branch):
235
+ self.assertEqual(
236
+ Device.objects.get(pk=self.device.pk).primary_ip4_id, self.ip.pk
237
+ )
238
+
239
+ def test_a_shared_management_address_is_recognised_as_shared(self):
240
+ from forward_netbox.utilities.primary_ip import (
241
+ _devices_sharing_management_address,
242
+ )
243
+
244
+ parent = Device.objects.create(
245
+ name="fw-parent",
246
+ site=self.device.site,
247
+ role=self.device.role,
248
+ device_type=self.device.device_type,
249
+ )
250
+ mgmt = Interface.objects.create(device=parent, name="mgmt", type="virtual")
251
+ IPAddress.objects.create(address="10.55.0.1/24", assigned_object=mgmt)
252
+
253
+ shared = _devices_sharing_management_address(
254
+ {"fw-vsys2": "no-interface", "r1": "no-interface"},
255
+ {"fw-vsys2": ["10.55.0.1"], "r1": ["10.66.0.1"]},
256
+ )
257
+
258
+ self.assertEqual(shared, {"fw-vsys2"})
259
+
217
260
  def test_a_tagged_device_ignores_the_management_address(self):
218
261
  other = Interface.objects.create(
219
262
  device=self.device, name="Loopback9", type="virtual"
@@ -23,7 +23,7 @@ class RuntimeDependencyCheckTest(SimpleTestCase):
23
23
  self.assertIsNotNone(_resolved_branching_version())
24
24
 
25
25
  def test_plugin_config_version_matches_package_release(self):
26
- self.assertEqual(NetboxForwardConfig.version, "3.0.2")
26
+ self.assertEqual(NetboxForwardConfig.version, "3.0.3")
27
27
 
28
28
  def test_exact_runtime_passes(self):
29
29
  _check_runtime_dependencies()