Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
582481a
fix: use validated-cache namespace for BG job gate + unconditional VC…
marcinpsk Mar 8, 2026
c716d9b
feat: multi-server librenms_id with JSON custom field and server mana…
marcinpsk Mar 7, 2026
175bd06
fix: strip stale derived fields in cable verify POST, preserve server…
marcinpsk Mar 7, 2026
df11f56
fix: reviewer findings — XSS, bool guards, cache TTL, VM safety, lega…
marcinpsk Mar 7, 2026
6ba4aa1
fix: code correctness improvements from refactor/librenms_id-rebased
marcinpsk Mar 7, 2026
b16d4a2
tests: expand test coverage from refactor/librenms_id-rebased
marcinpsk Mar 7, 2026
cda4bde
docs: update testing.md with additional test files and conventions
marcinpsk Mar 7, 2026
b501203
fix: reviewer findings batch 2 — XSS escape, bool guards, auto_save, …
marcinpsk Mar 7, 2026
5db057a
fix: resolve server_key from api when available in validate_device_fo…
marcinpsk Mar 7, 2026
6b440de
fix: reviewer findings batch 4 — error surfacing, cache TODO, proxy r…
marcinpsk Mar 8, 2026
3446747
fix: reviewer findings batch 6 — naming prefs resolver, test assertion
marcinpsk Mar 8, 2026
0ba62f9
fix: update test to match HEAD naming-source 'both empty' guard behavior
marcinpsk Mar 8, 2026
94799cc
style: ruff format
marcinpsk Mar 8, 2026
428224b
fix: avoid auto-discovery in VC member librenms_id check
marcinpsk Mar 8, 2026
605e400
fix: pass copied request to sub-view get_context_data in vms.py; warn…
marcinpsk Mar 8, 2026
5447cfd
fix: propagate server_key through cable enrichment methods
marcinpsk Mar 8, 2026
e1e81ca
fix: address valid PR #25 findings — common fixes
marcinpsk Mar 8, 2026
45c372a
fix: address two new PR #25 findings — Convert ID form target + serve…
marcinpsk Mar 8, 2026
020d0c9
tests: add coverage tests for 8 target files (all >95%)
marcinpsk Mar 8, 2026
835f96b
PR #25 fixes: VC guard, forms cache, virtual_chassis, vm_operations, …
marcinpsk Mar 8, 2026
99f135e
fix: always delegate VC lookup to get_librenms_sync_device; fix None …
marcinpsk Mar 8, 2026
f0e2337
fix: address PR #25 review findings (threads 23-28)
marcinpsk Mar 8, 2026
40bcf74
fix: port PR #22 common fixes + add list.py coverage tests
marcinpsk Mar 9, 2026
b8a1a2b
fix: multiple code hardening and test improvements
marcinpsk Mar 9, 2026
ac6b290
Create pull request template for contributions
bonzo81 Feb 19, 2026
96f379c
Remove checkbox to avoid task creation
bonzo81 Feb 27, 2026
971e0c5
fix: apply reviewer fixes (Threads 34-55) to pr/librems-id-multi-fixes
marcinpsk Mar 9, 2026
b4fed7a
Update pyproject.toml
marcinpsk Mar 9, 2026
2d80ab6
fix: batch 4 — ID zero guard, addresses list, hard-block collision, s…
marcinpsk Mar 9, 2026
b71c51b
fix: validate inventory response shape in get_device_inventory
marcinpsk Mar 9, 2026
94764c1
fix: librenms_id zero guard in discovery branches
marcinpsk Mar 9, 2026
5dc50e3
fix: RQ-first cancellation in bulk_import_vms, C901 comment clarifica…
marcinpsk Mar 9, 2026
bdf0c00
fix: always pass api into validate_device_for_import, hardware lookup…
marcinpsk Mar 9, 2026
8aa9e71
Fix payload shape guards for list_devices, get_device_vlans, get_inve…
marcinpsk Mar 9, 2026
6310439
fix: batch-6 CodeRabbit review — isinstance guards, VC domain fingerp…
marcinpsk Mar 9, 2026
bf7ab57
fix: batch-7 CR — strip_domain TypeError, vlans fallback guard, devic…
marcinpsk Mar 9, 2026
99d6868
Create pull request template for contributions
bonzo81 Feb 19, 2026
9ce45bf
Remove checkbox to avoid task creation
bonzo81 Feb 27, 2026
8bc0fa5
fix: batch-8 CR — C901 comment, test name/docstring clarity, remove o…
marcinpsk Mar 9, 2026
b6b9ebd
fix: batch-9 CR — None guard, device_type sync, cable ID guard, test …
marcinpsk Mar 9, 2026
719669a
fix: cache negative VC detection results; add regression tests and mo…
marcinpsk Mar 9, 2026
b793b79
fix: check dcim.add_virtualchassis permission before VC creation on i…
marcinpsk Mar 9, 2026
a35c236
fix: restore auto_save in get_librenms_id — normalize string IDs and …
marcinpsk Mar 9, 2026
11e6795
fix: batch-10 CR — serial in VC name, master serial normalization, up…
marcinpsk Mar 9, 2026
f9a3dbc
fix: skip create-only blockers for already-matched objects; add VM pe…
marcinpsk Mar 9, 2026
5f72979
fix: thread vc_detection_enabled into import, store resolved server_k…
marcinpsk Mar 9, 2026
e530a3e
fix: modules tab missing + issue #27 sync_name VM guard
marcinpsk Mar 9, 2026
87d219f
Fix issues #26 #28 #32 #33 #34 #36: import and VM operations robustness
marcinpsk Mar 10, 2026
63c18a6
fix: port production fixes from inventory-rebased
marcinpsk Mar 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
## Summary
Briefly describe what this PR does in plain English, and provide as much of the following information as possible.

## Motivation / Problem
What issue does this solve?
- Bug
- Feature
- Refactor
- Maintenance / cleanup

Link any related issues if applicable.

## Scope of Change
Delete items that don’t apply:

- Sync/Import logic
- NetBox models / ORM
- LibreNMS API interaction
- Config / settings
- Web UI / templates
- Database migrations
- Tests
- Docs only
- Other: <describe>

## How Was This Tested?
Delete items that don’t apply and describe briefly.

- Unit tests: <yes/no + what>
- Manual testing: <yes/no + what>
- Not tested: <explain why>

### Manual Test Steps (if applicable)
1.
2.
3.

## Risk Assessment
- Does this change affect existing users?
- Could this cause unintended imports / updates?

Explain briefly.

## Backwards Compatibility
- No breaking changes
- Breaking change (explain and document)

## Other Notes
Anything the maintainer(s) should pay particular attention to?
6 changes: 5 additions & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.15.4 # Use the latest version from https://github.com/astral-sh/ruff-pre-commit/releases
rev: v0.15.5 # Use the latest version from https://github.com/astral-sh/ruff-pre-commit/releases
hooks:
# Run the linter
- id: ruff-check
Expand All @@ -15,5 +15,9 @@ repos:
- id: end-of-file-fixer
- id: check-yaml
exclude: ^mkdocs\.yml$
- id: check-yaml
name: check-yaml (mkdocs.yml --unsafe)
args: [--unsafe]
files: ^mkdocs\.yml$
- id: check-added-large-files
- id: check-merge-conflict
20 changes: 17 additions & 3 deletions docs/development/testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,18 @@ The test suite covers all major plugin functionality. Tests are organized by the
| [test_sync_devices.py](../../netbox_librenms_plugin/tests/test_sync_devices.py) | Device sync views—field updates, platform creation, server mapping, legacy ID conversion |
| [test_sync_interfaces.py](../../netbox_librenms_plugin/tests/test_sync_interfaces.py) | Interface sync—port matching, attribute updates, MAC handling, librenms_id assignment |
| [test_sync_view_mismatch.py](../../netbox_librenms_plugin/tests/test_sync_view_mismatch.py) | Sync page context—device type mismatch detection and badge rendering |
| [test_coverage_device_fields.py](../../netbox_librenms_plugin/tests/test_coverage_device_fields.py) | Device field sync view—field update logic and device field mapping |
| [test_coverage_list.py](../../netbox_librenms_plugin/tests/test_coverage_list.py) | Import list view—background job decision, job result loading, and GET handler |
| [test_coverage_api.py](../../netbox_librenms_plugin/tests/test_coverage_api.py) | LibreNMS API client—malformed payload guards, error paths, and edge cases |
| [test_coverage_sync_view.py](../../netbox_librenms_plugin/tests/test_coverage_sync_view.py) | Sync view base class—context preparation and tab rendering |
| [test_coverage_filters.py](../../netbox_librenms_plugin/tests/test_coverage_filters.py) | Import filter logic—filter form processing and device count helpers |
| [test_sync_modules.py](../../netbox_librenms_plugin/tests/test_sync_modules.py) | Module sync—inventory matching, module type resolution, and normalization rules |
| [test_modules_view.py](../../netbox_librenms_plugin/tests/test_modules_view.py) | Module sync view—context preparation, table rendering, and module bay mapping |
| [test_tables_modules.py](../../netbox_librenms_plugin/tests/test_tables_modules.py) | Module tables—column rendering, row formatting, and action buttons |
| [test_permissions.py](../../netbox_librenms_plugin/tests/test_permissions.py) | Permission enforcement—mixin contracts, object-level permissions, and write guards |
| [test_vm_operations.py](../../netbox_librenms_plugin/tests/test_vm_operations.py) | VM operations—virtual machine sync, interface handling, and VM-specific views |
| [test_integration_sync.py](../../netbox_librenms_plugin/tests/test_integration_sync.py) | Integration tests—API client against local mock HTTP server |
| [test_integration_virtual_chassis.py](../../netbox_librenms_plugin/tests/test_integration_virtual_chassis.py) | Integration tests—VC detection, negative cache, multi-server cache isolation |
| [test_view_wiring.py](../../netbox_librenms_plugin/tests/test_view_wiring.py) | Smoke tests—view class MRO, mixin wiring, permission contracts, and template syntax |

Supporting files:
Expand Down Expand Up @@ -76,8 +86,11 @@ pytest netbox_librenms_plugin/tests/test_background_jobs.py -v
# Multi-server librenms_id tests
pytest netbox_librenms_plugin/tests/test_librenms_id.py -v

# Sync view tests (devices, interfaces)
pytest netbox_librenms_plugin/tests/test_sync_devices.py netbox_librenms_plugin/tests/test_sync_interfaces.py -v
# Sync view tests (devices, interfaces, modules)
pytest netbox_librenms_plugin/tests/test_sync_devices.py netbox_librenms_plugin/tests/test_sync_interfaces.py netbox_librenms_plugin/tests/test_sync_modules.py -v

# Integration tests (API client against mock HTTP server)
pytest netbox_librenms_plugin/tests/test_integration_sync.py -v

# Sync view mismatch detection and permission enforcement
pytest netbox_librenms_plugin/tests/test_sync_view_mismatch.py netbox_librenms_plugin/tests/test_permissions.py -v
Expand Down Expand Up @@ -110,9 +123,10 @@ pytest netbox_librenms_plugin/tests/ -v --lf
The test suite prioritizes speed and isolation so you can run tests frequently during development:

- **Mock-based**: Unit tests use `MagicMock` instead of real database objects. No Django database setup required.
- **Fast execution**: The full suite runs in under 0.5 seconds.
- **Fast execution**: The full suite runs in approximately 15-20 seconds (varies by environment).
- **Isolated**: Each test is independent with no shared state between tests.
- **No external network access**: Tests never call external services. Integration tests use a local loopback HTTP server (`mock_librenms_server.py`) to exercise the real API client against realistic HTTP responses without requiring a running LibreNMS instance.
- **Coverage exclusions**: Test files themselves are excluded from coverage reports (see `[tool.coverage.run]` omit list in `pyproject.toml`).

This approach means tests work identically in your local development environment, in the devcontainer, and in CI pipelines.

Expand Down
23 changes: 20 additions & 3 deletions netbox_librenms_plugin/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ def _get_librenms_poller_group_choices():
api = LibreNMSAPI()
success, poller_groups = api.get_poller_groups()

if success and poller_groups:
for group in poller_groups:
if success:
for group in poller_groups or []:
group_id = str(group.get("id", ""))
group_name = group.get("group_name", "")
group_descr = group.get("descr", "")
Expand Down Expand Up @@ -581,9 +581,26 @@ def _populate_librenms_locations(self):
from netbox_librenms_plugin.librenms_api import LibreNMSAPI

try:
# Instantiate the API client to resolve the authoritative server_key
# Determine server_key cheaply from settings to check cache before instantiating the API
try:
from netbox_librenms_plugin.models import LibreNMSSettings

_settings = LibreNMSSettings.objects.first()
_server_key = (_settings.selected_server if _settings else None) or "default"
except Exception:
_server_key = "default"

cache_key = get_location_choices_cache_key(_server_key)
cached_choices = cache.get(cache_key)
if cached_choices:
self.fields["librenms_location"].choices = cached_choices
return

# Cache miss — instantiate the API client and fetch
api = LibreNMSAPI()
# Recompute cache_key with the resolved server_key in case it differs from settings
cache_key = get_location_choices_cache_key(api.server_key)
# Second cache check: the resolved server_key may differ from the settings key
cached_choices = cache.get(cache_key)
if cached_choices:
self.fields["librenms_location"].choices = cached_choices
Expand Down
1 change: 1 addition & 0 deletions netbox_librenms_plugin/import_utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
get_active_cached_searches,
get_cache_metadata_key,
get_import_device_cache_key,
get_import_search_cache_key,
get_validated_device_cache_key,
)
from .device_operations import ( # noqa: F401
Expand Down
Loading