forward-netbox 2.3.0__tar.gz → 2.3.2__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 (292) hide show
  1. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/PKG-INFO +72 -89
  2. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/README.md +69 -86
  3. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/__init__.py +2 -2
  4. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/forms.py +13 -0
  5. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/navigation.py +1 -1
  6. forward_netbox-2.3.2/forward_netbox/queries/forward_devices.nqe +82 -0
  7. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/templates/forward_netbox/forwardsync_drift_report.html +10 -0
  8. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/templates/forward_netbox/inc/brand_bar.html +3 -3
  9. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/tests/test_brand_bar.py +2 -2
  10. forward_netbox-2.3.2/forward_netbox/tests/test_endpoints_import.py +51 -0
  11. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/tests/test_health.py +62 -0
  12. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/tests/test_sync.py +28 -0
  13. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/model_validation.py +3 -0
  14. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/query_fetch_execution.py +8 -0
  15. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/query_registry.py +8 -0
  16. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/sync_interface.py +5 -1
  17. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/views.py +17 -1
  18. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/pyproject.toml +5 -5
  19. forward_netbox-2.3.0/forward_netbox/queries/forward_devices.nqe +0 -41
  20. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/LICENSE +0 -0
  21. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/api/__init__.py +0 -0
  22. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/api/serializers.py +0 -0
  23. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/api/urls.py +0 -0
  24. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/api/views.py +0 -0
  25. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/choices.py +0 -0
  26. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/exceptions.py +0 -0
  27. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/filtersets.py +0 -0
  28. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/jobs.py +0 -0
  29. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/management/__init__.py +0 -0
  30. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/management/commands/__init__.py +0 -0
  31. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/management/commands/forward_apic_cimc_readiness_audit.py +0 -0
  32. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/management/commands/forward_apply_identity_audit.py +0 -0
  33. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/management/commands/forward_blocker_audit.py +0 -0
  34. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/management/commands/forward_collection_gap_alert.py +0 -0
  35. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/management/commands/forward_device_scope_reconciliation_audit.py +0 -0
  36. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/management/commands/forward_link_vsys_parents.py +0 -0
  37. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/management/commands/forward_metrics.py +0 -0
  38. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/management/commands/forward_module_readiness.py +0 -0
  39. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/management/commands/forward_primary_ip_audit.py +0 -0
  40. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/management/commands/forward_pushdown_profile.py +0 -0
  41. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/management/commands/forward_query_diff_coverage_audit.py +0 -0
  42. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/management/commands/forward_scope_ipam_audit.py +0 -0
  43. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/management/commands/forward_seed_ui_harness.py +0 -0
  44. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/management/commands/forward_stuck_job_alert.py +0 -0
  45. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/management/commands/forward_tag_delete_eligible.py +0 -0
  46. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/management/commands/forward_validation_org_query_audit.py +0 -0
  47. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/migrations/0001_initial.py +0 -0
  48. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/migrations/0002_add_coalesce_fields.py +0 -0
  49. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/migrations/0003_forwardingestionissue_context_fields.py +0 -0
  50. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/migrations/0004_forwardingestion_baseline_fields.py +0 -0
  51. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/migrations/0005_validation_and_reporting.py +0 -0
  52. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/migrations/0006_alter_forwardnqemap_netbox_model.py +0 -0
  53. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/migrations/0007_forwardingestion_persisted_change_counters.py +0 -0
  54. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/migrations/0008_alter_forwardnqemap_netbox_model.py +0 -0
  55. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/migrations/0009_alter_forwardnqemap_netbox_model.py +0 -0
  56. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/migrations/0010_forwardvalidationrun_override_applied_and_more.py +0 -0
  57. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/migrations/0011_forwardingestion_change_request_id.py +0 -0
  58. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/migrations/0012_forwardnqemap_query_reference.py +0 -0
  59. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/migrations/0013_execution_run_step.py +0 -0
  60. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/migrations/0014_execution_step_fetch_scope.py +0 -0
  61. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/migrations/0015_execution_step_apply_engine.py +0 -0
  62. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/migrations/0016_execution_step_query_metrics.py +0 -0
  63. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/migrations/0017_execution_step_row_counters.py +0 -0
  64. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/migrations/0018_execution_run_reconciliation_events.py +0 -0
  65. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/migrations/0019_forwardexecutionstep_query_parameters.py +0 -0
  66. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/migrations/0020_execution_step_operation.py +0 -0
  67. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/migrations/0021_add_fhrpgroup_nqe_map_choice.py +0 -0
  68. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/migrations/0022_alter_forwardnqemap_netbox_model.py +0 -0
  69. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/migrations/0023_split_ip_address_maps.py +0 -0
  70. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/migrations/0024_forwarddeviceanalysis.py +0 -0
  71. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/migrations/0025_device_analysis_netboxmodel.py +0 -0
  72. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/migrations/0026_forwarddeviceanalysis_collection_result.py +0 -0
  73. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/migrations/0027_alter_forwardexecutionrun_backend.py +0 -0
  74. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/migrations/0028_remove_forwardexecutionstep_run_and_more.py +0 -0
  75. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/migrations/0029_forward_parent_device_cf.py +0 -0
  76. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/migrations/0030_forwarddeviceanalysis_cve_ids.py +0 -0
  77. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/migrations/0031_encrypt_source_password.py +0 -0
  78. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/migrations/__init__.py +0 -0
  79. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/models.py +0 -0
  80. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/queries/__init__.py +0 -0
  81. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/queries/forward_aci_apic_cimc_inventory.nqe +0 -0
  82. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/queries/forward_aci_apic_nodes.nqe +0 -0
  83. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/queries/forward_aci_app_profiles.nqe +0 -0
  84. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/queries/forward_aci_bridge_domains.nqe +0 -0
  85. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/queries/forward_aci_command_inventory.nqe +0 -0
  86. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/queries/forward_aci_contracts.nqe +0 -0
  87. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/queries/forward_aci_endpoint_groups.nqe +0 -0
  88. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/queries/forward_aci_fabrics.nqe +0 -0
  89. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/queries/forward_aci_filters.nqe +0 -0
  90. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/queries/forward_aci_l3outs.nqe +0 -0
  91. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/queries/forward_aci_nodes.nqe +0 -0
  92. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/queries/forward_aci_pods.nqe +0 -0
  93. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/queries/forward_aci_static_port_bindings.nqe +0 -0
  94. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/queries/forward_aci_tenants.nqe +0 -0
  95. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/queries/forward_aci_vrfs.nqe +0 -0
  96. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/queries/forward_bgp_address_families.nqe +0 -0
  97. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/queries/forward_bgp_peer_address_families.nqe +0 -0
  98. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/queries/forward_bgp_peers.nqe +0 -0
  99. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/queries/forward_device_analysis.nqe +0 -0
  100. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/queries/forward_device_feature_tags.nqe +0 -0
  101. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/queries/forward_device_feature_tags_with_rules.nqe +0 -0
  102. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/queries/forward_device_models.nqe +0 -0
  103. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/queries/forward_device_models_with_netbox_aliases.nqe +0 -0
  104. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/queries/forward_device_types.nqe +0 -0
  105. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/queries/forward_device_vendors.nqe +0 -0
  106. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/queries/forward_devices_with_netbox_aliases.nqe +0 -0
  107. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/queries/forward_hsrp_groups.nqe +0 -0
  108. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/queries/forward_inferred_interface_cables.nqe +0 -0
  109. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/queries/forward_interfaces.nqe +0 -0
  110. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/queries/forward_inventory_items.nqe +0 -0
  111. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/queries/forward_ip_addresses_ipv4.nqe +0 -0
  112. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/queries/forward_ip_addresses_ipv6.nqe +0 -0
  113. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/queries/forward_ip_addresses_unassignable_diagnostics.nqe +0 -0
  114. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/queries/forward_locations.nqe +0 -0
  115. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/queries/forward_mac_addresses.nqe +0 -0
  116. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/queries/forward_modules.nqe +0 -0
  117. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/queries/forward_ospf_areas.nqe +0 -0
  118. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/queries/forward_ospf_instances.nqe +0 -0
  119. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/queries/forward_ospf_interfaces.nqe +0 -0
  120. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/queries/forward_peering_sessions.nqe +0 -0
  121. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/queries/forward_platforms.nqe +0 -0
  122. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/queries/forward_prefixes_ipv4.nqe +0 -0
  123. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/queries/forward_prefixes_ipv6.nqe +0 -0
  124. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/queries/forward_routing_import_diagnostics.nqe +0 -0
  125. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/queries/forward_virtual_chassis.nqe +0 -0
  126. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/queries/forward_vlans.nqe +0 -0
  127. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/queries/forward_vrfs.nqe +0 -0
  128. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/queries/netbox_utilities.nqe +0 -0
  129. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/signals.py +0 -0
  130. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/static/forward_netbox/img/fn-logo.svg +0 -0
  131. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/tables.py +0 -0
  132. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/template_content.py +0 -0
  133. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/templates/forward_netbox/forwarddriftpolicy.html +0 -0
  134. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/templates/forward_netbox/forwardingestion.html +0 -0
  135. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/templates/forward_netbox/forwardnqemap.html +0 -0
  136. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/templates/forward_netbox/forwardsource.html +0 -0
  137. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/templates/forward_netbox/forwardsync.html +0 -0
  138. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/templates/forward_netbox/forwardsync_dependency_preview.html +0 -0
  139. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/templates/forward_netbox/forwardsync_health.html +0 -0
  140. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/templates/forward_netbox/forwardsync_module_readiness.html +0 -0
  141. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/templates/forward_netbox/forwardsync_scope_reconciliation.html +0 -0
  142. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/templates/forward_netbox/forwardvalidationrun.html +0 -0
  143. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/templates/forward_netbox/inc/device_analysis_panel.html +0 -0
  144. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/templates/forward_netbox/inc/diff.html +0 -0
  145. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/templates/forward_netbox/inc/execution_insights.html +0 -0
  146. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/templates/forward_netbox/inc/logs_pending.html +0 -0
  147. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/templates/forward_netbox/inc/merge_form.html +0 -0
  148. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/templates/forward_netbox/inc/validation_force_allow_form.html +0 -0
  149. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/templates/forward_netbox/partials/change_explainability.html +0 -0
  150. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/templates/forward_netbox/partials/ingestion_all.html +0 -0
  151. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/templates/forward_netbox/partials/ingestion_merge_button.html +0 -0
  152. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/templates/forward_netbox/partials/ingestion_progress.html +0 -0
  153. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/templates/forward_netbox/partials/ingestion_statistics.html +0 -0
  154. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/templates/forward_netbox/partials/ingestion_status.html +0 -0
  155. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/templates/forward_netbox/partials/job_logs.html +0 -0
  156. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/templates/forward_netbox/partials/object_tabs.html +0 -0
  157. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/templates/forward_netbox/partials/stage_switcher_buttons.html +0 -0
  158. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/templates/forward_netbox/partials/validation_force_allow_button.html +0 -0
  159. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/templatetags/__init__.py +0 -0
  160. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/templatetags/forward_netbox_helpers.py +0 -0
  161. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/tests/__init__.py +0 -0
  162. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/tests/fixtures/aci_command_inventory_expected.json +0 -0
  163. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/tests/fixtures/aci_discovery_expected.json +0 -0
  164. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/tests/scenarios.py +0 -0
  165. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/tests/test_api_usage.py +0 -0
  166. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/tests/test_api_views.py +0 -0
  167. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/tests/test_apic_cimc_readiness_audit_command.py +0 -0
  168. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/tests/test_apply_engine.py +0 -0
  169. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/tests/test_apply_identity_audit.py +0 -0
  170. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/tests/test_branching.py +0 -0
  171. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/tests/test_bulk_adapter_parity.py +0 -0
  172. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/tests/test_bulk_merge.py +0 -0
  173. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/tests/test_bulk_merge_scale.py +0 -0
  174. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/tests/test_crypto.py +0 -0
  175. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/tests/test_dependency_preview_summary.py +0 -0
  176. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/tests/test_device_analysis_query.py +0 -0
  177. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/tests/test_device_scope_reconciliation_audit_command.py +0 -0
  178. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/tests/test_device_scope_tagging.py +0 -0
  179. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/tests/test_execution_insights_delete_label.py +0 -0
  180. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/tests/test_forms.py +0 -0
  181. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/tests/test_forward_api.py +0 -0
  182. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/tests/test_ingestion_merge.py +0 -0
  183. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/tests/test_interface_naming.py +0 -0
  184. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/tests/test_ip_address_dedup_query.py +0 -0
  185. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/tests/test_ipaddress_dup_global.py +0 -0
  186. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/tests/test_issue_rendering.py +0 -0
  187. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/tests/test_job_compat.py +0 -0
  188. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/tests/test_job_liveness.py +0 -0
  189. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/tests/test_jobs.py +0 -0
  190. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/tests/test_log_export.py +0 -0
  191. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/tests/test_logging.py +0 -0
  192. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/tests/test_migrations.py +0 -0
  193. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/tests/test_models.py +0 -0
  194. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/tests/test_module_readiness.py +0 -0
  195. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/tests/test_module_readiness_rollup.py +0 -0
  196. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/tests/test_plugin_integrations.py +0 -0
  197. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/tests/test_primary_ip.py +0 -0
  198. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/tests/test_primary_ip_audit.py +0 -0
  199. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/tests/test_primary_ip_integration.py +0 -0
  200. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/tests/test_query_binding.py +0 -0
  201. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/tests/test_query_diff_coverage_audit_command.py +0 -0
  202. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/tests/test_query_registry.py +0 -0
  203. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/tests/test_release_readiness_audit.py +0 -0
  204. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/tests/test_runtime_dependency_check.py +0 -0
  205. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/tests/test_scope_ipam_audit.py +0 -0
  206. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/tests/test_scope_matched_tags.py +0 -0
  207. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/tests/test_scope_module_ui.py +0 -0
  208. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/tests/test_sensitive_content.py +0 -0
  209. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/tests/test_stability_hardening.py +0 -0
  210. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/tests/test_sync_aci.py +0 -0
  211. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/tests/test_sync_facade.py +0 -0
  212. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/tests/test_sync_orchestration.py +0 -0
  213. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/tests/test_sync_runner_contracts.py +0 -0
  214. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/tests/test_sync_state.py +0 -0
  215. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/tests/test_synthetic_scenarios.py +0 -0
  216. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/tests/test_validation_org_query_audit_command.py +0 -0
  217. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/tests/test_vsys_parent.py +0 -0
  218. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/urls.py +0 -0
  219. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/__init__.py +0 -0
  220. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/api_usage.py +0 -0
  221. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/apply_engine.py +0 -0
  222. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/apply_engine_bulk.py +0 -0
  223. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/apply_engine_decision.py +0 -0
  224. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/apply_identity_audit.py +0 -0
  225. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/branch_budget.py +0 -0
  226. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/branching.py +0 -0
  227. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/bulk_merge.py +0 -0
  228. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/change_explainability.py +0 -0
  229. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/crypto.py +0 -0
  230. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/density_learning.py +0 -0
  231. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/device_analysis.py +0 -0
  232. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/direct_changes.py +0 -0
  233. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/drift_report.py +0 -0
  234. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/execution_ledger.py +0 -0
  235. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/execution_telemetry.py +0 -0
  236. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/fast_bootstrap_executor.py +0 -0
  237. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/fetch_artifacts.py +0 -0
  238. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/forward_api.py +0 -0
  239. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/forward_api_impl.py +0 -0
  240. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/health.py +0 -0
  241. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/health_apply_fetch.py +0 -0
  242. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/health_checks.py +0 -0
  243. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/health_summary_blocks.py +0 -0
  244. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/ingestion_issues.py +0 -0
  245. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/ingestion_merge.py +0 -0
  246. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/ingestion_presentation.py +0 -0
  247. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/interface_naming.py +0 -0
  248. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/job_compat.py +0 -0
  249. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/job_liveness.py +0 -0
  250. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/json_safe.py +0 -0
  251. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/logging.py +0 -0
  252. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/merge.py +0 -0
  253. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/model_contracts.py +0 -0
  254. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/module_readiness.py +0 -0
  255. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/multi_branch_lifecycle.py +0 -0
  256. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/plugin_integrations/__init__.py +0 -0
  257. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/plugin_integrations/registry.py +0 -0
  258. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/primary_ip.py +0 -0
  259. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/primary_ip_audit.py +0 -0
  260. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/query_binding.py +0 -0
  261. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/query_binding_resolution.py +0 -0
  262. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/query_diagnostics.py +0 -0
  263. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/query_fetch.py +0 -0
  264. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/runtime_guidance.py +0 -0
  265. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/scope_ipam_audit.py +0 -0
  266. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/scope_reconciliation.py +0 -0
  267. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/sensitive_content.py +0 -0
  268. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/single_branch_executor.py +0 -0
  269. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/snapshot_freshness.py +0 -0
  270. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/support_bundle_archive.py +0 -0
  271. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/sync.py +0 -0
  272. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/sync_aci.py +0 -0
  273. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/sync_cable.py +0 -0
  274. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/sync_contracts.py +0 -0
  275. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/sync_core_models.py +0 -0
  276. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/sync_device.py +0 -0
  277. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/sync_events.py +0 -0
  278. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/sync_execution.py +0 -0
  279. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/sync_facade.py +0 -0
  280. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/sync_inventory_module.py +0 -0
  281. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/sync_ipam.py +0 -0
  282. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/sync_orchestration.py +0 -0
  283. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/sync_primitives.py +0 -0
  284. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/sync_reporting.py +0 -0
  285. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/sync_routing.py +0 -0
  286. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/sync_routing_impl.py +0 -0
  287. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/sync_runner_adapters.py +0 -0
  288. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/sync_runner_contracts.py +0 -0
  289. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/sync_state.py +0 -0
  290. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/validation.py +0 -0
  291. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/validation_org_query.py +0 -0
  292. {forward_netbox-2.3.0 → forward_netbox-2.3.2}/forward_netbox/utilities/vsys_parent.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: forward-netbox
3
- Version: 2.3.0
3
+ Version: 2.3.2
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
@@ -8,7 +8,7 @@ Keywords: netbox,forward,plugin,sync,nqe
8
8
  Author: Craig Johnson
9
9
  Author-email: craigjohnson@forwardnetworks.com
10
10
  Requires-Python: >=3.10,<4.0
11
- Classifier: Development Status :: 5 - Production/Stable
11
+ Classifier: Development Status :: 4 - Beta
12
12
  Classifier: Framework :: Django
13
13
  Classifier: Intended Audience :: Information Technology
14
14
  Classifier: Intended Audience :: System Administrators
@@ -23,7 +23,7 @@ Classifier: Programming Language :: Python :: 3.14
23
23
  Classifier: Topic :: System :: Networking
24
24
  Requires-Dist: httpx (>0.26,<0.29)
25
25
  Requires-Dist: netboxlabs-netbox-branching (>=1.1.0)
26
- Requires-Dist: pyzipper (>=0.3.6,<0.4.0)
26
+ Requires-Dist: pyzipper (>=0.3.6,<0.5.0)
27
27
  Project-URL: Changelog, https://github.com/forwardnetworks/forward-netbox/blob/main/CHANGELOG.md
28
28
  Project-URL: Documentation, https://github.com/forwardnetworks/forward-netbox/tree/main/docs
29
29
  Project-URL: Homepage, https://github.com/forwardnetworks/forward-netbox
@@ -31,17 +31,77 @@ Project-URL: Issue Tracker, https://github.com/forwardnetworks/forward-netbox/is
31
31
  Project-URL: Repository, https://github.com/forwardnetworks/forward-netbox
32
32
  Description-Content-Type: text/markdown
33
33
 
34
- # Forward Field Integration
34
+ # Forward Integration for NetBox
35
35
 
36
- **Forward Field Integration** (`forward_netbox`) is a NetBox plugin that syncs Forward inventory into NetBox through direct Forward API connectivity and NQE while preserving the branch-backed sync, diff, and merge workflow.
36
+ **Forward Integration for NetBox** (`forward_netbox`) is a NetBox plugin that syncs Forward Networks inventory into NetBox.
37
37
 
38
- Forward 26.6 is the baseline for async NQE.
38
+ [![PyPI](https://img.shields.io/pypi/v/forward-netbox)](https://pypi.org/project/forward-netbox/)
39
+ [![CI](https://github.com/forwardnetworks/forward-netbox/actions/workflows/ci.yml/badge.svg)](https://github.com/forwardnetworks/forward-netbox/actions/workflows/ci.yml)
40
+
41
+ ## Status
42
+
43
+ - **Support model:** field integration reference — **not** an officially
44
+ supported Forward Networks product.
45
+ - **Requires:** NetBox `4.6.4`, `netbox-branching` `1.1.0+`; Forward `26.6`
46
+ baseline for async NQE (full matrix in
47
+ [Release Compatibility](#release-compatibility)).
48
+ - **Distribution:** PyPI (`forward-netbox`) + GitHub releases.
49
+
50
+ ## What It Does
51
+
52
+ It pulls your Forward-discovered inventory into NetBox — devices, interfaces, IP addresses, prefixes, VLANs, VRFs, cables, LAGs, MAC addresses, and inventory items. It runs Forward NQE against a chosen snapshot, stages every change in a `netbox_branching` branch so you can review the diff, then merges when it looks right.
53
+
54
+ On top of the import it adds scope control (sync only devices carrying chosen Forward tags), orphan pruning, per-device analysis (reachability, connectivity blast-radius, CVE exposure), a drift report, and snapshot selection.
55
+
56
+ ## What It Does Not Do
57
+
58
+ - **It does not write back to Forward.** The sync is one-way, Forward → NetBox;
59
+ Forward stays the source of truth and the plugin keeps NetBox populated from
60
+ what Forward collected. (The drift report only *compares* the two.)
61
+ - **It is not a source of truth for Forward configuration or intent** — it
62
+ populates NetBox from Forward's collected snapshot, nothing more.
63
+ - **It does not require** the optional `netbox-routing` / `netbox-peering-manager`
64
+ plugins unless you enable the beta BGP/OSPF maps.
65
+
66
+ ## Screenshots
67
+
68
+ **Sync — health, enabled models, and actions**
69
+
70
+ ![Forward sync detail](docs/assets/screenshots/sync-detail.png)
71
+
72
+ **Staged ingestion — progress, snapshot metrics, and issues**
73
+
74
+ ![Forward ingestion detail](docs/assets/screenshots/ingestion-diff.png)
75
+
76
+ **Drift report — per-model NetBox-vs-Forward divergence**
77
+
78
+ ![Drift report](docs/assets/screenshots/drift-report.png)
79
+
80
+ **Forward sources**
81
+
82
+ ![Forward sources list](docs/assets/screenshots/sources.png)
83
+
84
+ ## Architecture
85
+
86
+ Forward NQE runs against a selected snapshot to fetch inventory, each model's
87
+ rows are staged into a `netbox_branching` branch as a reviewable per-model diff,
88
+ and you merge when the changes look correct. Large baselines can use a
89
+ `Fast bootstrap` direct-write backend; steady-state runs use Branching with
90
+ Forward `nqe-diffs` so every change is reviewable. See the
91
+ [Architecture Flow](docs/02_Reference/architecture-flow.md) reference for detail.
39
92
 
40
93
  ## Release Compatibility
41
94
 
95
+ Latest release requires NetBox `4.6.4` and `netbox-branching` `1.1.0+`. Expand for the full per-release history and notes.
96
+
97
+ <details>
98
+ <summary>Release compatibility history</summary>
99
+
42
100
  | Plugin Release | NetBox Version | Status |
43
101
  | --- | --- | --- |
44
- | `v2.3.0` | `4.6.4` required; needs netbox-branching `1.1.0+` | Current release; GA/enterprise hardening: encrypted Forward credential at rest, PyPI Trusted Publishing + SBOM, Prometheus metrics + stuck-job alert, populated-DB upgrade test, dead-code removal (multi_branch/density-learning), reliability fixes (jittered/Retry-After backoff, SaaS rate clamp, PK-anchored device prune), and supported-product framing. Drop-in from 2.2.5 — stored credentials auto-encrypt on save; rotating SECRET_KEY requires re-entering them. |
102
+ | `v2.3.2` | `4.6.4` required; needs netbox-branching `1.1.0+` | Current release; Feature: optional import of Forward SNMP endpoints (e.g. Avocent console servers) as NetBox devices — off by default (`sync_endpoints`), enabled per source and scoped by the same device tags. |
103
+ | `v2.3.1` | `4.6.4` required; needs netbox-branching `1.1.0+` | Superseded by `v2.3.2`; |
104
+ | `v2.3.0` | `4.6.4` required; needs netbox-branching `1.1.0+` | Superseded by `v2.3.1`; GA/enterprise hardening: encrypted Forward credential at rest, PyPI Trusted Publishing + SBOM, Prometheus metrics + stuck-job alert, populated-DB upgrade test, dead-code removal (multi_branch/density-learning), reliability fixes (jittered/Retry-After backoff, SaaS rate clamp, PK-anchored device prune), and supported-product framing. Drop-in from 2.2.5 — stored credentials auto-encrypt on save; rotating SECRET_KEY requires re-entering them. |
45
105
  | `v2.2.5` | `4.6.4` required; needs netbox-branching `1.1.0+` | Superseded by `v2.3.0`; Feature: operator-selectable **Sync Device Tags** — pick which Forward device tags (e.g. `Mgmt_*`) become NetBox device tags (replaces the hardcoded feature-tag set); Fix dependency-preview AttributeError + vsys job pile-up guard (hung pending); test/require NetBox 4.6.4 |
46
106
  | `v2.2.4` | `4.6.3` required; needs netbox-branching `1.1.0+` | Superseded by `v2.2.5`; Hotfix: device-analysis NQE (bare foreach) errored refresh + CVE list; surface job errors into job.data |
47
107
  | `v2.2.3` | `4.6.3` required; needs netbox-branching `1.1.0+` | Superseded by `v2.2.4`; Field-feedback fixes: delete-count labeling, vsys/vdom auto-link, skip empty VRFs, per-device CVE list, churn pinpoint, query-ID status clarify |
@@ -137,91 +197,14 @@ Forward 26.6 is the baseline for async NQE.
137
197
  | `v0.3.0.1` | `4.5.8` validated; `4.5.x` only | Superseded by `v0.3.1` |
138
198
  | `v0.3.0` | `4.5.8` validated; `4.5.x` only | Superseded by `v0.3.0.1` |
139
199
 
140
- ## Version History
141
-
142
- | Release | Summary |
143
- | --- | --- |
144
- | `v1.5.0.1` | Fixes platform NQE query (`normalizePlatformName`), adds `--overwrite` to validation-org repair, hardens org-publish commit to retry on 409 INVALID_CHANGE_PATH. |
145
- | `v1.5.0` | Hardens ingest throughput: adaptive async-NQE poll backoff, ndjson streaming, webhook/event-rule signal suppression during apply, targeted validation on existing objects (skips DB-hitting uniqueness checks in both bulk engine paths), and async advanced-reachability trigger (FWD-53559). Full suite green on NetBox 4.5.9 and 4.6.2. |
146
- | `v1.4.3` | Hardens query provenance with source-backed query-id repair during preflight, adds async execution path readiness for 26.6 with resilient NDJSON/JSONL result handling, and proves CIMC/APIC platform/type updates from command-source evidence while preserving prior 1.4 protections. |
147
- | `v1.4.2` | Adds CIMC platform separation, visible query-drift repair and dependency preview on the sync detail page, and keeps module-bay merge hardening plus parent-interface description preservation. |
148
- | `v1.4.1.1` | Prevents optional module sync from creating `dcim.modulebay` side-effect changes during merge, skips missing module bays with a readiness/import warning, and keeps LAG member rows from clearing existing parent interface descriptions. |
149
- | `v1.4.1` | Publishes the 1.4 patch release line with query-ID drift remediation and support-bundle diagnostics on top of the parent-device contract and release surfaces. |
150
- | `v1.3.6` | Enforces a hard parent-device sync contract so child models cannot run without `dcim.device`, preventing stale sync configs from skipping the device shard and breaking dependent imports. |
151
- | `v1.3.5.5` | Adds compressed support-bundle ZIP downloads with optional password protection and folds live source/query-drift/data-file diagnostics into the troubleshooting bundle. |
152
- | `v1.3.5.4` | Republishes the `v1.3.5.3` query-contract hardening as the prior patch release. |
153
- | `v1.3.5.3` | Preserves the claimed-step and payload-compaction protections from `v1.3.5.2`, adds strict shipped-query parameter-contract validation, strips legacy tag aliases from runtime NQE payloads, and keeps support-bundle previews summary-only. |
154
- | `v1.3.5.2` | Prevents shard execution drift by tying resume/overlap workers to the claimed execution step and compacts sync execution payloads (`plan_items`, workload previews, and advisory branch summaries) so large runs remain user-visible but lightweight in UI/log exports. |
155
- | `v1.3.5.1` | Removes the raw `model_results` payload from sync telemetry summaries and stops unparameterized query IDs from inheriting source-level tag parameters, which keeps sync-detail rendering responsive while preserving the saved-query-ID path. |
156
- | `v1.3.5` | Tightens the saved-query-ID path for 1.3.x, keeps shipped maps parameter-compatible with `forward_netbox_shard_keys`, and uses command-inventory signals to avoid misclassifying ACI platforms during repeat syncs. |
157
- | `v1.3.4` | Makes non-retryable Branching merge errors operator-visible by persisting the failure reason before the job terminates, marks branches still stuck in `Merging` as `Failed`, preserves timeout/transient retry behavior, and adds disabled-by-default async NQE client support for the future Forward 26.6 execution API. |
158
- | `v1.3.3` | Refreshes shipped NQE syntax so saved query IDs accept the standard `forward_netbox_shard_keys` parameter payload, republishes the saved validation-folder query set, and validates the affected saved query IDs against a live Forward SaaS dataset. |
159
- | `v1.3.2` | Adds optional `netbox-cisco-aci` plugin support with disabled-by-default ACI fabric, pod, node, tenant, VRF, and filter maps; keeps deeper ACI policy maps conservative until source identity is proven; and hardens duplicate ACI node observations so repeat syncs remain no-op when source data is unchanged. |
160
- | `v1.3.1` | Fixes repeat prefix sync accounting by treating unchanged NetBox `ipam.prefix` rows as unchanged, avoids dependency VRF metadata rewrites from prefix/IP/FHRP imports, removes the legacy sync column-filter shard path, and preserves the `v1.3.0` parameterized NQE path. |
161
- | `v1.3.0` | Eliminates default Forward NQE column-filter shard fetches in favor of query-side `forward_netbox_shard_keys` parameters, keeps local shard safety filtering, and preserves branch boundaries while reducing Forward SaaS API/NQE pressure. |
162
- | `v1.2.3` | Coalesces compatible sibling shard column-filter fetches into bounded EQUALS_ANY requests, caches prefetched sibling rows locally to avoid repeated Forward calls, and surfaces local Branching change-explainability summaries in support bundles and the ingestion UI. |
163
- | `v1.2.2` | Adds operator-visible Forward API usage budgets/rate evidence in Sync Health and support bundles, extends repeat-sync no-op hardening across key adapters, and persists successful staged deletes into ingestion statistics so active delete shards are visible before merge accounting catches up. |
164
- | `v1.2.1` | Fixes repeat prefix sync churn where otherwise unchanged `ipam.prefix` rows could be updated only because the VRF foreign key was re-resolved; built-in prefix maps now use exact `prefix + vrf` identity while prefix shard fetches still use parameterized NQE. |
165
- | `v1.2.0` | Adds optional NetBox-native HSRP/VRRP FHRP import from Forward native FHRP state, bounded access/native interface VLAN assignment from existing site-scoped VLANs, keeps FHRP upgrade behavior safe for existing 1.1 IPAM data, and hardens current NetBox job-test compatibility. |
166
- | `v1.1.1` | Adds optional NetBox-native HSRP/FHRP import from Forward native FHRP state, keeps FHRP upgrade behavior safe for existing 1.1 IPAM data, and hardens current NetBox job-test compatibility. |
167
- | `v1.1.0` | Adds Forward SaaS API request pacing, parameterized prefix shard execution, single-pass interface NQE, configured max-shard persistence in smoke evidence, and release-validation gates for API/NQE scale validation. |
168
- | `v1.0.0` | Introduced the first `v1.0.0` release line and initial API/NQE release validation flow before the 1.1 runtime and request-pacing enhancements. |
169
- | `v0.9.4.6` | Tightens delete-heavy `dcim.device` cleanup planning to about 500 planned delete rows per 10k branch-change budget after live shard evidence showed the earlier estimate was still too high. |
170
- | `v0.9.4.5` | Plans delete-heavy `dcim.device` cleanup shards with a conservative row budget so tag-scope prune runs do not pack thousands of cascading device deletes into one Branching shard. |
171
- | `v0.9.4.4` | Clarifies large branching progress by clamping utilization display to 100% during intermediate accounting overshoots and showing current shard row progress in the ingestion UI. |
172
- | `v0.9.4.3` | Converts NetBox protected-reference delete failures into dependency skips so large tag-scope prune/device cleanup runs continue without shard-failing delete rows. |
173
- | `v0.9.4.1.1` | Keeps the shared 4.5/4.6 branch line, execution ledger, support logging, and scale hardening while preserving the read-only advisory surfaces from `v0.9.0`. |
174
- | `v0.9.0` | Adds read-only analysis, workload preview, advisory summaries, and native log export for troubleshooting while keeping lifecycle enrichment and predict deferred. |
175
- | `v0.8.6.3` | Hardens beta routing scope resolution, filters invalid BGP ASN rows in shipped NQE, skips positionless virtual-chassis rows conservatively, and lets fast bootstrap retain its diff baseline when only optional model issues remain. |
176
- | `v0.8.6.2` | Hardens issue and job-log rendering for JSON safety when unexpected nested payload objects leak into failure data. |
177
- | `v0.8.6.1` | Clarifies NQE map bulk edit labels and help text so operators use repository query paths and understand query IDs are resolved automatically during sync and diff execution. |
178
- | `v0.8.6` | Publishes flattened built-in NQE to Forward org repositories, filters IPv4 host/any/loopback prefix artifacts, reports IP rows missing imported parent prefixes on full baselines, and prevents stale virtual-chassis/device/routing row failures from blocking unrelated models. |
179
- | `v0.8.5` | Makes the beta routing and module maps broadly available by default, preserves the conservative bundled virtual chassis map, handles Forward repository query lookups that return a `queries` list, and makes failed sync activity show the terminal failure instead of stale row heartbeat text. |
180
- | `v0.8.3` | Isolates stale or invalid per-model query output, rejects virtual-chassis rows missing `vc_position`, records row issues without aborting later multi-branch shards, and prevents dirty runs from becoming diff baselines. |
181
- | `v0.8.2` | Adds portable repository `query_path` execution with Forward-backed selectors, true native bulk edit for publishing bundled NQE into the Forward Org Repository, binding selected maps to repository paths, restoring bundled raw NQE, and clearer skipping for IP address rows whose interface cannot be resolved. |
182
- | `v0.8.1.1` | Emits `vc_position` in the built-in virtual chassis NQE map for vPC and MLAG memberships so NetBox does not reject virtual chassis device assignments without a member position. |
183
- | `v0.8.1` | Runs fast bootstrap inside native NetBox change tracking, shows branchless ingestion changes from `ObjectChange` rows, updates fast-bootstrap counters from real object changes, warns about undersized worker timeouts, and retries transient Forward API HTTP timeouts/gateway responses. |
184
- | `v0.8.0` | Adds an opt-in fast bootstrap direct-write backend for trusted large baselines, keeps NQE validation and row adapters shared with Branching, and skips LAG cable endpoints that NetBox cannot cable directly. |
185
- | `v0.7.1` | Keeps the NetBox-native multi-branch workflow stable while hardening cable ingestion, retry handling, and shard re-planning for large runs. |
186
- | `v0.7.0` | Splits the remaining sync orchestration, reporting, and validation helpers into dedicated boundaries, adds shard heartbeat visibility, and preserves the NetBox-native branch workflow. |
187
- | `v0.6.5` | Adds audited validation force-allow overrides and routing evidence enrichment while reducing skipped routing rows through conservative NQE-side identity inference. |
188
- | `v0.6.4` | Adds beta optional routing and peering imports for `netbox-routing` and `netbox-peering-manager`, including BGP peers, BGP address families, OSPF objects, peering sessions, routing diagnostics, and query-ID-aware built-in map handling. |
189
- | `v0.6.3` | Models Forward aggregate interfaces as native NetBox LAGs, attaches member interfaces through `Interface.lag`, and keeps the MTU value sourced from Forward's normalized interface field. |
190
- | `v0.6.2` | Canonicalizes duplicate global-table IP address rows by host IP before import and records row-scoped apply/delete failures as ingestion issues without aborting the rest of the shard. |
191
- | `v0.6.1` | Filters interface IP rows that NetBox cannot assign, such as subnet network IDs and IPv4 broadcasts, while reporting aggregate diagnostics for filtered addresses. |
192
- | `v0.6.0` | Adds beta native `dcim.module` import for chassis modules and similar bay-aware hardware, improves inventory item normalization, and avoids duplicate generic inventory rows when beta module sync is enabled. |
193
- | `v0.5.9.1` | Keeps job logs visible during execution by persisting plugin log entries into the native NetBox job log tab while preserving the full plugin ingestion log view. |
194
- | `v0.5.9` | Balances query preflight and workload fetch with bounded parallelism, reducing long planning pauses on large datasets. |
195
- | `v0.5.8` | Defers event flushing until commit so large prefix ingestions do not trip transaction state changes mid-run. |
196
- | `v0.5.5` | Applies a consistent model conflict policy for cable sync rows: skip occupied-interface conflicts, aggregate warning spam, and keep non-conflict updates/creates unchanged. |
197
- | `v0.5.4` | Persists ingestion change counters so list/detail values stay consistent after branch merge cleanup, matching merge summaries. |
198
- | `v0.5.3` | Surfaces preflight activity and elapsed phase timing on sync detail, emits early phase logs before ingestion rows, and sets source status to `Syncing` while runs are active. |
199
- | `v0.5.2.1` | Fixes plugin admin version display and ships inferred cable query parser compatibility update (no `let` declarations) while preserving synthetic endpoint filtering. |
200
- | `v0.4.0` | Corrects built-in IPv4/IPv6 prefix NQE filters to exclude host routes (`/32` and `/128`) from prefix import and validates the behavior against a live smoke dataset. |
201
- | `v0.3.1` | Adds optional data-file-aware device type alias maps, a Device Type Library alias data-file builder, and documentation for the snapshot requirement while keeping the default no-data-file maps available. |
202
- | `v0.3.0.1` | Fixes the validation-run list UI by removing unsupported edit actions from read-only validation records, and adds Playwright coverage for the validation-run list route. |
203
- | `v0.3.0` | Adds the NetBox 4.5.8-validated harness architecture with first-class validation runs, drift policies, query-fetch boundaries, model-result reporting, and Playwright-covered UI workflow validation. |
204
- | `v0.2.4` | Hardens native multi-branch resilience with adaptive shard splitting and retry on branch-budget overflow, plus model-density tracking to keep large initial syncs within NetBox branching guidance. |
205
- | `v0.2.3` | Adds native sync preflight validation before full multi-branch planning so invalid model/query rows fail earlier in the UI/API run path. |
206
- | `v0.2.2` | NQE-only correction release: filters zero-length prefixes, broadens interface coverage for IP assignment targets, and enforces inventory `part_id` length limits. |
207
- | `v0.2.1` | Makes NetBox-native multi-branch execution the only UI/API sync path and exposes the branch budget in the sync form. |
208
- | `v0.2.0` | Adds NetBox-native multi-branch baseline syncs for large datasets, uses NetBox outbound proxy routing for Forward API calls, and keeps branch event queues bounded during large imports. |
209
- | `v0.1.6.0` | Adds explicit diff baselines, Forward `nqe-diffs` execution for eligible `query_id` maps, and updated large-dataset guidance for baseline versus incremental syncs. |
210
- | `v0.1.5.1` | Patch release that validates and hardens null-VRF coalesce behavior and inventory-item serial bounds against the live dataset. |
211
- | `v0.1.5` | Fixes null VRF coalesce handling, imports loopback interfaces for IP attachment, and hardens inventory-item identity fallbacks. |
212
- | `v0.1.4.2` | CI/package patch release that applies repository formatting/import-order fixes and publishes a clean artifact line. |
213
- | `v0.1.4.1` | Patch release that bounds built-in `dcim.virtualchassis` names/domains to NetBox field limits. |
214
- | `v0.1.4` | Hardened built-in NQE mappings and docs for large real-world datasets. |
215
- | `v0.1.3` | Enforced deterministic model identity contracts during sync ingestion. |
216
- | `v0.1.2` | Improved ingestion safety, diagnostics, and compatibility with custom NetBox data. |
217
- | `v0.1.1` | Added pagination, shared built-in NQE helpers, and release/doc cleanup. |
218
- | `v0.1.0` | Initial unsupported NetBox plugin release with built-in Forward sync workflow and seeded NQE maps. |
200
+ </details>
219
201
 
220
202
  ## Support
221
203
 
222
- Forward Field Integration is an officially maintained Forward Networks integration
223
- for NetBox. Supported NetBox and `netbox-branching` versions are listed in the
224
- Release Compatibility table above; support targets the latest released version.
204
+ This is a **field integration** maintained by a Forward Networks SE — a reference
205
+ integration, **not an officially supported Forward Networks product**, provided
206
+ as-is with no SLA. Supported NetBox and `netbox-branching` versions are listed in
207
+ the Release Compatibility table above; fixes target the latest released version.
225
208
 
226
209
  - **Bugs / feature requests:** open a GitHub issue using the provided templates.
227
210
  - **Security vulnerabilities:** report privately per [SECURITY.md](SECURITY.md) —
@@ -1,14 +1,74 @@
1
- # Forward Field Integration
1
+ # Forward Integration for NetBox
2
2
 
3
- **Forward Field Integration** (`forward_netbox`) is a NetBox plugin that syncs Forward inventory into NetBox through direct Forward API connectivity and NQE while preserving the branch-backed sync, diff, and merge workflow.
3
+ **Forward Integration for NetBox** (`forward_netbox`) is a NetBox plugin that syncs Forward Networks inventory into NetBox.
4
4
 
5
- Forward 26.6 is the baseline for async NQE.
5
+ [![PyPI](https://img.shields.io/pypi/v/forward-netbox)](https://pypi.org/project/forward-netbox/)
6
+ [![CI](https://github.com/forwardnetworks/forward-netbox/actions/workflows/ci.yml/badge.svg)](https://github.com/forwardnetworks/forward-netbox/actions/workflows/ci.yml)
7
+
8
+ ## Status
9
+
10
+ - **Support model:** field integration reference — **not** an officially
11
+ supported Forward Networks product.
12
+ - **Requires:** NetBox `4.6.4`, `netbox-branching` `1.1.0+`; Forward `26.6`
13
+ baseline for async NQE (full matrix in
14
+ [Release Compatibility](#release-compatibility)).
15
+ - **Distribution:** PyPI (`forward-netbox`) + GitHub releases.
16
+
17
+ ## What It Does
18
+
19
+ It pulls your Forward-discovered inventory into NetBox — devices, interfaces, IP addresses, prefixes, VLANs, VRFs, cables, LAGs, MAC addresses, and inventory items. It runs Forward NQE against a chosen snapshot, stages every change in a `netbox_branching` branch so you can review the diff, then merges when it looks right.
20
+
21
+ On top of the import it adds scope control (sync only devices carrying chosen Forward tags), orphan pruning, per-device analysis (reachability, connectivity blast-radius, CVE exposure), a drift report, and snapshot selection.
22
+
23
+ ## What It Does Not Do
24
+
25
+ - **It does not write back to Forward.** The sync is one-way, Forward → NetBox;
26
+ Forward stays the source of truth and the plugin keeps NetBox populated from
27
+ what Forward collected. (The drift report only *compares* the two.)
28
+ - **It is not a source of truth for Forward configuration or intent** — it
29
+ populates NetBox from Forward's collected snapshot, nothing more.
30
+ - **It does not require** the optional `netbox-routing` / `netbox-peering-manager`
31
+ plugins unless you enable the beta BGP/OSPF maps.
32
+
33
+ ## Screenshots
34
+
35
+ **Sync — health, enabled models, and actions**
36
+
37
+ ![Forward sync detail](docs/assets/screenshots/sync-detail.png)
38
+
39
+ **Staged ingestion — progress, snapshot metrics, and issues**
40
+
41
+ ![Forward ingestion detail](docs/assets/screenshots/ingestion-diff.png)
42
+
43
+ **Drift report — per-model NetBox-vs-Forward divergence**
44
+
45
+ ![Drift report](docs/assets/screenshots/drift-report.png)
46
+
47
+ **Forward sources**
48
+
49
+ ![Forward sources list](docs/assets/screenshots/sources.png)
50
+
51
+ ## Architecture
52
+
53
+ Forward NQE runs against a selected snapshot to fetch inventory, each model's
54
+ rows are staged into a `netbox_branching` branch as a reviewable per-model diff,
55
+ and you merge when the changes look correct. Large baselines can use a
56
+ `Fast bootstrap` direct-write backend; steady-state runs use Branching with
57
+ Forward `nqe-diffs` so every change is reviewable. See the
58
+ [Architecture Flow](docs/02_Reference/architecture-flow.md) reference for detail.
6
59
 
7
60
  ## Release Compatibility
8
61
 
62
+ Latest release requires NetBox `4.6.4` and `netbox-branching` `1.1.0+`. Expand for the full per-release history and notes.
63
+
64
+ <details>
65
+ <summary>Release compatibility history</summary>
66
+
9
67
  | Plugin Release | NetBox Version | Status |
10
68
  | --- | --- | --- |
11
- | `v2.3.0` | `4.6.4` required; needs netbox-branching `1.1.0+` | Current release; GA/enterprise hardening: encrypted Forward credential at rest, PyPI Trusted Publishing + SBOM, Prometheus metrics + stuck-job alert, populated-DB upgrade test, dead-code removal (multi_branch/density-learning), reliability fixes (jittered/Retry-After backoff, SaaS rate clamp, PK-anchored device prune), and supported-product framing. Drop-in from 2.2.5 — stored credentials auto-encrypt on save; rotating SECRET_KEY requires re-entering them. |
69
+ | `v2.3.2` | `4.6.4` required; needs netbox-branching `1.1.0+` | Current release; Feature: optional import of Forward SNMP endpoints (e.g. Avocent console servers) as NetBox devices — off by default (`sync_endpoints`), enabled per source and scoped by the same device tags. |
70
+ | `v2.3.1` | `4.6.4` required; needs netbox-branching `1.1.0+` | Superseded by `v2.3.2`; |
71
+ | `v2.3.0` | `4.6.4` required; needs netbox-branching `1.1.0+` | Superseded by `v2.3.1`; GA/enterprise hardening: encrypted Forward credential at rest, PyPI Trusted Publishing + SBOM, Prometheus metrics + stuck-job alert, populated-DB upgrade test, dead-code removal (multi_branch/density-learning), reliability fixes (jittered/Retry-After backoff, SaaS rate clamp, PK-anchored device prune), and supported-product framing. Drop-in from 2.2.5 — stored credentials auto-encrypt on save; rotating SECRET_KEY requires re-entering them. |
12
72
  | `v2.2.5` | `4.6.4` required; needs netbox-branching `1.1.0+` | Superseded by `v2.3.0`; Feature: operator-selectable **Sync Device Tags** — pick which Forward device tags (e.g. `Mgmt_*`) become NetBox device tags (replaces the hardcoded feature-tag set); Fix dependency-preview AttributeError + vsys job pile-up guard (hung pending); test/require NetBox 4.6.4 |
13
73
  | `v2.2.4` | `4.6.3` required; needs netbox-branching `1.1.0+` | Superseded by `v2.2.5`; Hotfix: device-analysis NQE (bare foreach) errored refresh + CVE list; surface job errors into job.data |
14
74
  | `v2.2.3` | `4.6.3` required; needs netbox-branching `1.1.0+` | Superseded by `v2.2.4`; Field-feedback fixes: delete-count labeling, vsys/vdom auto-link, skip empty VRFs, per-device CVE list, churn pinpoint, query-ID status clarify |
@@ -104,91 +164,14 @@ Forward 26.6 is the baseline for async NQE.
104
164
  | `v0.3.0.1` | `4.5.8` validated; `4.5.x` only | Superseded by `v0.3.1` |
105
165
  | `v0.3.0` | `4.5.8` validated; `4.5.x` only | Superseded by `v0.3.0.1` |
106
166
 
107
- ## Version History
108
-
109
- | Release | Summary |
110
- | --- | --- |
111
- | `v1.5.0.1` | Fixes platform NQE query (`normalizePlatformName`), adds `--overwrite` to validation-org repair, hardens org-publish commit to retry on 409 INVALID_CHANGE_PATH. |
112
- | `v1.5.0` | Hardens ingest throughput: adaptive async-NQE poll backoff, ndjson streaming, webhook/event-rule signal suppression during apply, targeted validation on existing objects (skips DB-hitting uniqueness checks in both bulk engine paths), and async advanced-reachability trigger (FWD-53559). Full suite green on NetBox 4.5.9 and 4.6.2. |
113
- | `v1.4.3` | Hardens query provenance with source-backed query-id repair during preflight, adds async execution path readiness for 26.6 with resilient NDJSON/JSONL result handling, and proves CIMC/APIC platform/type updates from command-source evidence while preserving prior 1.4 protections. |
114
- | `v1.4.2` | Adds CIMC platform separation, visible query-drift repair and dependency preview on the sync detail page, and keeps module-bay merge hardening plus parent-interface description preservation. |
115
- | `v1.4.1.1` | Prevents optional module sync from creating `dcim.modulebay` side-effect changes during merge, skips missing module bays with a readiness/import warning, and keeps LAG member rows from clearing existing parent interface descriptions. |
116
- | `v1.4.1` | Publishes the 1.4 patch release line with query-ID drift remediation and support-bundle diagnostics on top of the parent-device contract and release surfaces. |
117
- | `v1.3.6` | Enforces a hard parent-device sync contract so child models cannot run without `dcim.device`, preventing stale sync configs from skipping the device shard and breaking dependent imports. |
118
- | `v1.3.5.5` | Adds compressed support-bundle ZIP downloads with optional password protection and folds live source/query-drift/data-file diagnostics into the troubleshooting bundle. |
119
- | `v1.3.5.4` | Republishes the `v1.3.5.3` query-contract hardening as the prior patch release. |
120
- | `v1.3.5.3` | Preserves the claimed-step and payload-compaction protections from `v1.3.5.2`, adds strict shipped-query parameter-contract validation, strips legacy tag aliases from runtime NQE payloads, and keeps support-bundle previews summary-only. |
121
- | `v1.3.5.2` | Prevents shard execution drift by tying resume/overlap workers to the claimed execution step and compacts sync execution payloads (`plan_items`, workload previews, and advisory branch summaries) so large runs remain user-visible but lightweight in UI/log exports. |
122
- | `v1.3.5.1` | Removes the raw `model_results` payload from sync telemetry summaries and stops unparameterized query IDs from inheriting source-level tag parameters, which keeps sync-detail rendering responsive while preserving the saved-query-ID path. |
123
- | `v1.3.5` | Tightens the saved-query-ID path for 1.3.x, keeps shipped maps parameter-compatible with `forward_netbox_shard_keys`, and uses command-inventory signals to avoid misclassifying ACI platforms during repeat syncs. |
124
- | `v1.3.4` | Makes non-retryable Branching merge errors operator-visible by persisting the failure reason before the job terminates, marks branches still stuck in `Merging` as `Failed`, preserves timeout/transient retry behavior, and adds disabled-by-default async NQE client support for the future Forward 26.6 execution API. |
125
- | `v1.3.3` | Refreshes shipped NQE syntax so saved query IDs accept the standard `forward_netbox_shard_keys` parameter payload, republishes the saved validation-folder query set, and validates the affected saved query IDs against a live Forward SaaS dataset. |
126
- | `v1.3.2` | Adds optional `netbox-cisco-aci` plugin support with disabled-by-default ACI fabric, pod, node, tenant, VRF, and filter maps; keeps deeper ACI policy maps conservative until source identity is proven; and hardens duplicate ACI node observations so repeat syncs remain no-op when source data is unchanged. |
127
- | `v1.3.1` | Fixes repeat prefix sync accounting by treating unchanged NetBox `ipam.prefix` rows as unchanged, avoids dependency VRF metadata rewrites from prefix/IP/FHRP imports, removes the legacy sync column-filter shard path, and preserves the `v1.3.0` parameterized NQE path. |
128
- | `v1.3.0` | Eliminates default Forward NQE column-filter shard fetches in favor of query-side `forward_netbox_shard_keys` parameters, keeps local shard safety filtering, and preserves branch boundaries while reducing Forward SaaS API/NQE pressure. |
129
- | `v1.2.3` | Coalesces compatible sibling shard column-filter fetches into bounded EQUALS_ANY requests, caches prefetched sibling rows locally to avoid repeated Forward calls, and surfaces local Branching change-explainability summaries in support bundles and the ingestion UI. |
130
- | `v1.2.2` | Adds operator-visible Forward API usage budgets/rate evidence in Sync Health and support bundles, extends repeat-sync no-op hardening across key adapters, and persists successful staged deletes into ingestion statistics so active delete shards are visible before merge accounting catches up. |
131
- | `v1.2.1` | Fixes repeat prefix sync churn where otherwise unchanged `ipam.prefix` rows could be updated only because the VRF foreign key was re-resolved; built-in prefix maps now use exact `prefix + vrf` identity while prefix shard fetches still use parameterized NQE. |
132
- | `v1.2.0` | Adds optional NetBox-native HSRP/VRRP FHRP import from Forward native FHRP state, bounded access/native interface VLAN assignment from existing site-scoped VLANs, keeps FHRP upgrade behavior safe for existing 1.1 IPAM data, and hardens current NetBox job-test compatibility. |
133
- | `v1.1.1` | Adds optional NetBox-native HSRP/FHRP import from Forward native FHRP state, keeps FHRP upgrade behavior safe for existing 1.1 IPAM data, and hardens current NetBox job-test compatibility. |
134
- | `v1.1.0` | Adds Forward SaaS API request pacing, parameterized prefix shard execution, single-pass interface NQE, configured max-shard persistence in smoke evidence, and release-validation gates for API/NQE scale validation. |
135
- | `v1.0.0` | Introduced the first `v1.0.0` release line and initial API/NQE release validation flow before the 1.1 runtime and request-pacing enhancements. |
136
- | `v0.9.4.6` | Tightens delete-heavy `dcim.device` cleanup planning to about 500 planned delete rows per 10k branch-change budget after live shard evidence showed the earlier estimate was still too high. |
137
- | `v0.9.4.5` | Plans delete-heavy `dcim.device` cleanup shards with a conservative row budget so tag-scope prune runs do not pack thousands of cascading device deletes into one Branching shard. |
138
- | `v0.9.4.4` | Clarifies large branching progress by clamping utilization display to 100% during intermediate accounting overshoots and showing current shard row progress in the ingestion UI. |
139
- | `v0.9.4.3` | Converts NetBox protected-reference delete failures into dependency skips so large tag-scope prune/device cleanup runs continue without shard-failing delete rows. |
140
- | `v0.9.4.1.1` | Keeps the shared 4.5/4.6 branch line, execution ledger, support logging, and scale hardening while preserving the read-only advisory surfaces from `v0.9.0`. |
141
- | `v0.9.0` | Adds read-only analysis, workload preview, advisory summaries, and native log export for troubleshooting while keeping lifecycle enrichment and predict deferred. |
142
- | `v0.8.6.3` | Hardens beta routing scope resolution, filters invalid BGP ASN rows in shipped NQE, skips positionless virtual-chassis rows conservatively, and lets fast bootstrap retain its diff baseline when only optional model issues remain. |
143
- | `v0.8.6.2` | Hardens issue and job-log rendering for JSON safety when unexpected nested payload objects leak into failure data. |
144
- | `v0.8.6.1` | Clarifies NQE map bulk edit labels and help text so operators use repository query paths and understand query IDs are resolved automatically during sync and diff execution. |
145
- | `v0.8.6` | Publishes flattened built-in NQE to Forward org repositories, filters IPv4 host/any/loopback prefix artifacts, reports IP rows missing imported parent prefixes on full baselines, and prevents stale virtual-chassis/device/routing row failures from blocking unrelated models. |
146
- | `v0.8.5` | Makes the beta routing and module maps broadly available by default, preserves the conservative bundled virtual chassis map, handles Forward repository query lookups that return a `queries` list, and makes failed sync activity show the terminal failure instead of stale row heartbeat text. |
147
- | `v0.8.3` | Isolates stale or invalid per-model query output, rejects virtual-chassis rows missing `vc_position`, records row issues without aborting later multi-branch shards, and prevents dirty runs from becoming diff baselines. |
148
- | `v0.8.2` | Adds portable repository `query_path` execution with Forward-backed selectors, true native bulk edit for publishing bundled NQE into the Forward Org Repository, binding selected maps to repository paths, restoring bundled raw NQE, and clearer skipping for IP address rows whose interface cannot be resolved. |
149
- | `v0.8.1.1` | Emits `vc_position` in the built-in virtual chassis NQE map for vPC and MLAG memberships so NetBox does not reject virtual chassis device assignments without a member position. |
150
- | `v0.8.1` | Runs fast bootstrap inside native NetBox change tracking, shows branchless ingestion changes from `ObjectChange` rows, updates fast-bootstrap counters from real object changes, warns about undersized worker timeouts, and retries transient Forward API HTTP timeouts/gateway responses. |
151
- | `v0.8.0` | Adds an opt-in fast bootstrap direct-write backend for trusted large baselines, keeps NQE validation and row adapters shared with Branching, and skips LAG cable endpoints that NetBox cannot cable directly. |
152
- | `v0.7.1` | Keeps the NetBox-native multi-branch workflow stable while hardening cable ingestion, retry handling, and shard re-planning for large runs. |
153
- | `v0.7.0` | Splits the remaining sync orchestration, reporting, and validation helpers into dedicated boundaries, adds shard heartbeat visibility, and preserves the NetBox-native branch workflow. |
154
- | `v0.6.5` | Adds audited validation force-allow overrides and routing evidence enrichment while reducing skipped routing rows through conservative NQE-side identity inference. |
155
- | `v0.6.4` | Adds beta optional routing and peering imports for `netbox-routing` and `netbox-peering-manager`, including BGP peers, BGP address families, OSPF objects, peering sessions, routing diagnostics, and query-ID-aware built-in map handling. |
156
- | `v0.6.3` | Models Forward aggregate interfaces as native NetBox LAGs, attaches member interfaces through `Interface.lag`, and keeps the MTU value sourced from Forward's normalized interface field. |
157
- | `v0.6.2` | Canonicalizes duplicate global-table IP address rows by host IP before import and records row-scoped apply/delete failures as ingestion issues without aborting the rest of the shard. |
158
- | `v0.6.1` | Filters interface IP rows that NetBox cannot assign, such as subnet network IDs and IPv4 broadcasts, while reporting aggregate diagnostics for filtered addresses. |
159
- | `v0.6.0` | Adds beta native `dcim.module` import for chassis modules and similar bay-aware hardware, improves inventory item normalization, and avoids duplicate generic inventory rows when beta module sync is enabled. |
160
- | `v0.5.9.1` | Keeps job logs visible during execution by persisting plugin log entries into the native NetBox job log tab while preserving the full plugin ingestion log view. |
161
- | `v0.5.9` | Balances query preflight and workload fetch with bounded parallelism, reducing long planning pauses on large datasets. |
162
- | `v0.5.8` | Defers event flushing until commit so large prefix ingestions do not trip transaction state changes mid-run. |
163
- | `v0.5.5` | Applies a consistent model conflict policy for cable sync rows: skip occupied-interface conflicts, aggregate warning spam, and keep non-conflict updates/creates unchanged. |
164
- | `v0.5.4` | Persists ingestion change counters so list/detail values stay consistent after branch merge cleanup, matching merge summaries. |
165
- | `v0.5.3` | Surfaces preflight activity and elapsed phase timing on sync detail, emits early phase logs before ingestion rows, and sets source status to `Syncing` while runs are active. |
166
- | `v0.5.2.1` | Fixes plugin admin version display and ships inferred cable query parser compatibility update (no `let` declarations) while preserving synthetic endpoint filtering. |
167
- | `v0.4.0` | Corrects built-in IPv4/IPv6 prefix NQE filters to exclude host routes (`/32` and `/128`) from prefix import and validates the behavior against a live smoke dataset. |
168
- | `v0.3.1` | Adds optional data-file-aware device type alias maps, a Device Type Library alias data-file builder, and documentation for the snapshot requirement while keeping the default no-data-file maps available. |
169
- | `v0.3.0.1` | Fixes the validation-run list UI by removing unsupported edit actions from read-only validation records, and adds Playwright coverage for the validation-run list route. |
170
- | `v0.3.0` | Adds the NetBox 4.5.8-validated harness architecture with first-class validation runs, drift policies, query-fetch boundaries, model-result reporting, and Playwright-covered UI workflow validation. |
171
- | `v0.2.4` | Hardens native multi-branch resilience with adaptive shard splitting and retry on branch-budget overflow, plus model-density tracking to keep large initial syncs within NetBox branching guidance. |
172
- | `v0.2.3` | Adds native sync preflight validation before full multi-branch planning so invalid model/query rows fail earlier in the UI/API run path. |
173
- | `v0.2.2` | NQE-only correction release: filters zero-length prefixes, broadens interface coverage for IP assignment targets, and enforces inventory `part_id` length limits. |
174
- | `v0.2.1` | Makes NetBox-native multi-branch execution the only UI/API sync path and exposes the branch budget in the sync form. |
175
- | `v0.2.0` | Adds NetBox-native multi-branch baseline syncs for large datasets, uses NetBox outbound proxy routing for Forward API calls, and keeps branch event queues bounded during large imports. |
176
- | `v0.1.6.0` | Adds explicit diff baselines, Forward `nqe-diffs` execution for eligible `query_id` maps, and updated large-dataset guidance for baseline versus incremental syncs. |
177
- | `v0.1.5.1` | Patch release that validates and hardens null-VRF coalesce behavior and inventory-item serial bounds against the live dataset. |
178
- | `v0.1.5` | Fixes null VRF coalesce handling, imports loopback interfaces for IP attachment, and hardens inventory-item identity fallbacks. |
179
- | `v0.1.4.2` | CI/package patch release that applies repository formatting/import-order fixes and publishes a clean artifact line. |
180
- | `v0.1.4.1` | Patch release that bounds built-in `dcim.virtualchassis` names/domains to NetBox field limits. |
181
- | `v0.1.4` | Hardened built-in NQE mappings and docs for large real-world datasets. |
182
- | `v0.1.3` | Enforced deterministic model identity contracts during sync ingestion. |
183
- | `v0.1.2` | Improved ingestion safety, diagnostics, and compatibility with custom NetBox data. |
184
- | `v0.1.1` | Added pagination, shared built-in NQE helpers, and release/doc cleanup. |
185
- | `v0.1.0` | Initial unsupported NetBox plugin release with built-in Forward sync workflow and seeded NQE maps. |
167
+ </details>
186
168
 
187
169
  ## Support
188
170
 
189
- Forward Field Integration is an officially maintained Forward Networks integration
190
- for NetBox. Supported NetBox and `netbox-branching` versions are listed in the
191
- Release Compatibility table above; support targets the latest released version.
171
+ This is a **field integration** maintained by a Forward Networks SE — a reference
172
+ integration, **not an officially supported Forward Networks product**, provided
173
+ as-is with no SLA. Supported NetBox and `netbox-branching` versions are listed in
174
+ the Release Compatibility table above; fixes target the latest released version.
192
175
 
193
176
  - **Bugs / feature requests:** open a GitHub issue using the provided templates.
194
177
  - **Security vulnerabilities:** report privately per [SECURITY.md](SECURITY.md) —
@@ -6,9 +6,9 @@ except ModuleNotFoundError: # pragma: no cover - tooling imports outside NetBox
6
6
 
7
7
  class NetboxForwardConfig(PluginConfig):
8
8
  name = "forward_netbox"
9
- verbose_name = "Forward Field Integration"
9
+ verbose_name = "Forward"
10
10
  description = "Sync Forward data into NetBox using built-in NQE queries."
11
- version = "2.3.0"
11
+ version = "2.3.2"
12
12
  base_url = "forward"
13
13
  min_version = "4.6.4"
14
14
 
@@ -436,6 +436,16 @@ class ForwardSourceForm(NetBoxModelForm):
436
436
  "filtered in NetBox."
437
437
  ),
438
438
  )
439
+ self.fields["sync_endpoints"] = forms.BooleanField(
440
+ required=False,
441
+ label="Import SNMP Endpoints as Devices",
442
+ help_text=(
443
+ "Also import Forward SNMP endpoints (generic SSH/SNMP devices "
444
+ "Forward collects but does not model as first-class devices, "
445
+ "e.g. Avocent console servers) as NetBox devices, scoped by the "
446
+ "same device tags."
447
+ ),
448
+ )
439
449
  self.fields["sync_device_tags"] = FlexibleMultipleChoiceField(
440
450
  required=False,
441
451
  choices=(),
@@ -605,6 +615,7 @@ class ForwardSourceForm(NetBoxModelForm):
605
615
  self.fields["device_tag_include_tags"].initial = include_initial
606
616
  self.fields["device_tag_exclude_tags"].initial = exclude_initial
607
617
  self.fields["sync_device_tags"].initial = sync_tags_initial
618
+ self.fields["sync_endpoints"].initial = bool(parameters.get("sync_endpoints"))
608
619
  self.fields["device_tag_include_tags"].choices = [
609
620
  (tag, tag) for tag in include_initial
610
621
  ]
@@ -840,6 +851,7 @@ class ForwardSourceForm(NetBoxModelForm):
840
851
  ),
841
852
  "apply_device_scope_tags": bool(cleaned.get("apply_device_scope_tags")),
842
853
  "sync_device_tags": sync_device_tags,
854
+ "sync_endpoints": bool(cleaned.get("sync_endpoints")),
843
855
  }
844
856
  self.instance.type = source_type
845
857
  self.instance.url = (
@@ -1033,6 +1045,7 @@ class ForwardSourceForm(NetBoxModelForm):
1033
1045
  self.cleaned_data.get("apply_device_scope_tags")
1034
1046
  ),
1035
1047
  "sync_device_tags": sync_device_tags,
1048
+ "sync_endpoints": bool(self.cleaned_data.get("sync_endpoints")),
1036
1049
  }
1037
1050
  self.instance.status = ForwardSourceStatusChoices.NEW
1038
1051
  return super().save(*args, **kwargs)
@@ -79,7 +79,7 @@ device_analysis = PluginMenuItem(
79
79
  )
80
80
 
81
81
  menu = PluginMenu(
82
- label="Forward Field Integration",
82
+ label="Forward",
83
83
  icon_class="mdi mdi-cloud-sync",
84
84
  groups=(
85
85
  ("Data Sync", (source, sync, ingestion, validation_run)),
@@ -0,0 +1,82 @@
1
+ /**
2
+ * @intent Devices collected by Forward (plus optional SNMP endpoints)
3
+ * @description Devices to add or update in NetBox via POST/PATCH to
4
+ * /api/dcim/devices/. When sync_endpoints is true, generic SNMP endpoints that
5
+ * Forward collects but does not model as first-class devices (e.g. Avocent
6
+ * console servers) are also emitted as device rows, identified from standard
7
+ * MIB-2 (sysName/sysDescr/sysObjectId) with per-vendor overlays, and scoped by
8
+ * the same device tags.
9
+ */
10
+
11
+ import "netbox_utilities";
12
+
13
+ @query
14
+ f(forward_netbox_shard_keys: List<String>, sync_endpoints: Bool, device_tag_include_tags: List<String>, device_tag_include_match: String, device_tag_exclude_tags: List<String>) =
15
+ foreach row in (
16
+ (
17
+ foreach device in network.devices
18
+ where device.snapshotInfo.result == DeviceSnapshotResult.completed
19
+ where device.platform.vendor != Vendor.FORWARD_CUSTOM
20
+ where isEmpty(forward_netbox_shard_keys) || device.name in forward_netbox_shard_keys
21
+ let model = toString(device.platform.model)
22
+ let role_name = replace(toString(device.platform.deviceType), "DeviceType.", "")
23
+ let site_name = if isPresent(device.locationName) then toLowerCase(device.locationName) else "unknown"
24
+ let platform_name = normalizeDevicePlatformName(device)
25
+ let manufacturer_name = canonicalManufacturerName(device.platform.vendor)
26
+ let manufacturer_slug = slugify(manufacturer_name)
27
+ select {
28
+ name: device.name,
29
+ manufacturer: manufacturer_name,
30
+ device_type: model,
31
+ device_type_slug: slugifyNetboxModel(model),
32
+ site: site_name,
33
+ site_slug: slugify(site_name),
34
+ role: role_name,
35
+ role_slug: slugify(role_name),
36
+ role_color: "9e9e9e",
37
+ platform: platform_name,
38
+ platform_slug: slugify(platform_name),
39
+ status: "active",
40
+ manufacturer_slug: manufacturer_slug
41
+ }
42
+ )
43
+ +
44
+ (
45
+ // SNMP endpoints (opt-in): generic SSH/SNMP devices Forward collects but
46
+ // does not model. Generic identity from MIB-2; Avocent overlay by enterprise
47
+ // OID 10418. Scoped by the same device tags (endpoints carry tagNames).
48
+ foreach endpoint in network.endpoints
49
+ where sync_endpoints
50
+ where !isEmpty(endpoint.snmpOutputs)
51
+ where isEmpty(device_tag_include_tags)
52
+ || (device_tag_include_match == "all"
53
+ && all(foreach tag in device_tag_include_tags select tag in endpoint.tagNames))
54
+ || (device_tag_include_match != "all"
55
+ && any(foreach tag in device_tag_include_tags select tag in endpoint.tagNames))
56
+ where isEmpty(device_tag_exclude_tags)
57
+ || !any(foreach tag in device_tag_exclude_tags select tag in endpoint.tagNames)
58
+ let sysDescrOpt = max(foreach o in endpoint.snmpOutputs where o.requestedOid == "1.3.6.1.2.1.1.1" select max(foreach e in o.rawOidEntries select e.rawValue))
59
+ let sysObjIdOpt = max(foreach o in endpoint.snmpOutputs where o.requestedOid == "1.3.6.1.2.1.1.2" select max(foreach e in o.rawOidEntries select e.rawValue))
60
+ let sysDescr = if isPresent(sysDescrOpt) then sysDescrOpt else "SNMP Endpoint"
61
+ let isAvocent = matches(if isPresent(sysObjIdOpt) then sysObjIdOpt else "", "*10418*")
62
+ let ep_manuf = if isAvocent then "Avocent" else replaceRegexMatches(sysDescr, re` .*`, "")
63
+ let ep_role = if isAvocent then "Console Server" else "SNMP Endpoint"
64
+ let ep_site = if isPresent(endpoint.locationName) then toLowerCase(endpoint.locationName) else "unknown"
65
+ select {
66
+ name: endpoint.name,
67
+ manufacturer: ep_manuf,
68
+ device_type: sysDescr,
69
+ device_type_slug: slugifyNetboxModel(sysDescr),
70
+ site: ep_site,
71
+ site_slug: slugify(ep_site),
72
+ role: ep_role,
73
+ role_slug: slugify(ep_role),
74
+ role_color: "9e9e9e",
75
+ platform: ep_manuf,
76
+ platform_slug: slugify(ep_manuf),
77
+ status: "active",
78
+ manufacturer_slug: slugify(ep_manuf)
79
+ }
80
+ )
81
+ )
82
+ select row;
@@ -11,6 +11,16 @@
11
11
  {% endblock extra_controls %}
12
12
 
13
13
  {% block content %}
14
+ {% if drift_stale %}
15
+ <div class="alert alert-warning d-flex align-items-center" role="alert">
16
+ <i class="mdi mdi-alert me-2" aria-hidden="true"></i>
17
+ <div>
18
+ {% trans "This drift is computed from a dependency preview, but a newer sync has run since — the numbers below are stale." %}
19
+ {% trans "Preview:" %} {{ preview_at|placeholder }} · {% trans "Last sync:" %} {{ last_sync_at|placeholder }}.
20
+ {% trans "Re-run Preview Dependencies for current drift." %}
21
+ </div>
22
+ </div>
23
+ {% endif %}
14
24
  <div class="row mb-3">
15
25
  <div class="col col-md-4">
16
26
  <div class="card">
@@ -1,7 +1,7 @@
1
1
  {% load static %}
2
2
  {% load i18n %}
3
3
  {% comment %}
4
- Forward Field Integration brand bar. Self-contained, theme-aware (logo wordmark
4
+ Forward Integration for NetBox brand bar. Self-contained, theme-aware (logo wordmark
5
5
  uses currentColor), no global NetBox style overrides. ff3506 is Forward's accent.
6
6
  {% endcomment %}
7
7
  <style>
@@ -10,8 +10,8 @@ uses currentColor), no global NetBox style overrides. ff3506 is Forward's accent
10
10
  .fwd-brand-bar .fwd-name{font-weight:600;font-size:.8rem;letter-spacing:.01em;}
11
11
  .fwd-brand-bar .fwd-tag{font-size:.72rem;opacity:.6;margin-left:auto;}
12
12
  </style>
13
- <div class="fwd-brand-bar" title="Forward Field Integration">
13
+ <div class="fwd-brand-bar" title="Forward Integration for NetBox">
14
14
  <img class="fwd-logo" src="{% static 'forward_netbox/img/fn-logo.svg' %}" alt="Forward">
15
- <span class="fwd-name">{% trans "Field Integration" %}</span>
15
+ <span class="fwd-name">{% trans "Forward" %}</span>
16
16
  <span class="fwd-tag">{% trans "Forward Networks · NetBox" %}</span>
17
17
  </div>
@@ -3,14 +3,14 @@ from django.test import TestCase
3
3
 
4
4
 
5
5
  class BrandBarTemplateTest(TestCase):
6
- """The Forward Field Integration brand bar must render the logo + label, and
6
+ """The Forward Integration for NetBox brand bar must render the logo + label, and
7
7
  must NOT leak its template comment as visible text (a multi-line {# #} comment
8
8
  is not a comment in Django and rendered literally on the page)."""
9
9
 
10
10
  def test_brand_bar_renders_without_leaking_comment(self):
11
11
  html = render_to_string("forward_netbox/inc/brand_bar.html")
12
12
  self.assertIn("fwd-brand-bar", html)
13
- self.assertIn("Field Integration", html)
13
+ self.assertIn(">Forward</span>", html)
14
14
  self.assertIn("fn-logo.svg", html)
15
15
  # The {% comment %} block must be stripped — none of its words appear.
16
16
  self.assertNotIn("Self-contained", html)