Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
243 commits
Select commit Hold shift + click to select a range
1520c8d
feat(inventory): modules/inventory sync tab with mapping rules
marcinpsk Mar 31, 2026
c53b0c4
fix tests: update db-fallback tests to match new RQ-only cancellation…
marcinpsk Apr 1, 2026
b2fe27d
fix: updated tests
marcinpsk Apr 1, 2026
a60d601
Apply CR findings: code quality, test, docs, and template fixes
marcinpsk Apr 1, 2026
b04c67a
Apply second batch of CR findings on pr/inventory-core
marcinpsk Apr 1, 2026
ca7af1a
Apply CR findings batch 3: test hardening, PlatformMapping lazy impor…
marcinpsk Apr 1, 2026
cc7cb42
cr: batch 4 — prefetch_related, deterministic export, test improvements
marcinpsk Apr 1, 2026
1a9df23
cr: batch 5 — normalization scoping bug, test fixes
marcinpsk Apr 1, 2026
4a73896
cr: batch 6 — normalization rule caching, test correctness
marcinpsk Apr 1, 2026
a5f3b45
fix: FPC slot int/str comparison, stale docstring, test patch targets
marcinpsk Apr 1, 2026
8776a0d
fix: surface ambiguous platform, preloaded-rules fallback, serial mis…
marcinpsk Apr 1, 2026
5d6d856
fix: canonical librenms_id lookup, None guard, transceiver transparen…
marcinpsk Apr 1, 2026
ab85324
Apply CR batch 10 fixes
marcinpsk Apr 2, 2026
a6aece3
Apply CR batch 11 fixes
marcinpsk Apr 2, 2026
75e1a51
fix: normalize librenms_hardware/os to lowercase, fix convert_speed_t…
marcinpsk Apr 2, 2026
281c835
fix(js): address PR #258 review findings
marcinpsk Apr 2, 2026
881c111
fix: handle unsaved manufacturer in normalization, fix JS modal/fetch…
marcinpsk Apr 2, 2026
aa443be
fix: type annotation, non-positive librenms_id guard, htmx label list…
marcinpsk Apr 2, 2026
0773a2f
fix: use _PLACEHOLDER_VALUES for serial normalization, fix docstring
marcinpsk Apr 2, 2026
ae4c50a
Fix CR batch: device_type ambiguity, platform MOR, cache invalidation…
marcinpsk Apr 2, 2026
1e29fc5
Promote SKIP_TYPES and _NON_HARDWARE_CLASSES to module-level constants
marcinpsk Apr 2, 2026
7e70201
Fix find_matching_platform docstring and non-positive string librenms…
marcinpsk Apr 2, 2026
32562e7
fix: normalize placeholder serials and txr_type in modules_view
marcinpsk Apr 2, 2026
513932b
Fix whitespace-only librenms_id, BUILTIN model placeholder, FPC-scope…
marcinpsk Apr 3, 2026
16ee302
Fix non-integer librenms_id passthrough, stale cache on missing ID, e…
marcinpsk Apr 3, 2026
7dfd436
fix: normalize _GENERIC_CONTAINER_MODELS to lowercase; embed librenms…
marcinpsk Apr 3, 2026
727198d
fix: treat duplicate-serial module conflicts as ambiguous instead of …
marcinpsk Apr 3, 2026
ab8dd7d
fix: clear stale cache on legacy payload; ungate generic-model filter…
marcinpsk Apr 3, 2026
521932e
Remove dead vc_requested assignment left by rebase
marcinpsk Apr 14, 2026
316caa1
fix: VC zero-based detection all-zeros guard; align VC-perm tests wit…
marcinpsk Apr 14, 2026
44836e9
fix: CR batch 12 — serial normalization, conflict disambiguation, mod…
marcinpsk Apr 14, 2026
eceb492
fix: address deferred CR findings from issues #53-#56
marcinpsk Apr 14, 2026
e96b3f3
fix: address 3 remaining CR findings from PR #50
marcinpsk Apr 14, 2026
7464ea5
refactor: drop _extract_inventory_list legacy-list fallback
marcinpsk Apr 15, 2026
ca5f8ef
fix: race conditions, class-aware mappings, stale snapshot in module …
marcinpsk Apr 15, 2026
7a202bd
fix: normalize placeholder serials in UpdateModuleSerialView, fix reg…
marcinpsk Apr 15, 2026
45e8078
fix: lock module row before updating serial in UpdateModuleSerialView
marcinpsk Apr 15, 2026
87400d5
fix: use fullmatch+expand in _find_parent_module_id regex matching
marcinpsk Apr 15, 2026
b56da37
Merge branch 'develop' into pr/inventory-core
bonzo81 Apr 15, 2026
b4a331d
fix: address CR review batch - regex, tests, docs
marcinpsk Apr 15, 2026
d87863f
revert: restore original docs/usage_tips/virtual_chassis.md
marcinpsk Apr 15, 2026
7ac2017
fix: revert bulk_import cancellation, VC comment, VM docstring, sync …
marcinpsk Apr 15, 2026
fbb8d80
fix: restore naming resolution and VC logic lost during rebase
marcinpsk Apr 15, 2026
338ef60
revert: restore original README.md and virtual_chassis.md
marcinpsk Apr 15, 2026
793797a
fix: improve ambiguity test assertion and error message wording
marcinpsk Apr 15, 2026
87772d0
fix: CR review - modal close, test line refs, generic e2e
marcinpsk Apr 17, 2026
be40fd8
Merge branch 'develop' into pr/inventory-core
marcinpsk Apr 17, 2026
4d418be
docs: update instruction files for accuracy after v0.4.4-v0.4.6 changes
bonzo81 Apr 20, 2026
fb79e87
Merge pull request #278 from bonzo81/docs/update-instructions-for-rel…
bonzo81 Apr 20, 2026
631777e
Merge branch 'develop' into pr/inventory-core
marcinpsk Apr 21, 2026
53e76b2
fix: three bugs in module inventory sync reported in PR #261 review
marcinpsk Apr 27, 2026
a1c0be8
fix: improve module table readability in dark mode
marcinpsk Apr 27, 2026
c23a2da
feat: split Mappings into its own navigation group
marcinpsk Apr 27, 2026
c04e700
refactor: reorder navigation groups to Import, Status Check, Mappings…
marcinpsk Apr 27, 2026
0946700
fix: remove table-light from mismatch modal thead for dark mode
marcinpsk Apr 27, 2026
c82fef8
fix: replace table-danger/warning cell backgrounds with text colors i…
marcinpsk Apr 27, 2026
0105892
fix: remove all row background highlighting from module sync table
marcinpsk Apr 27, 2026
04c9b8d
refactor: reorder Mappings group — all mappings first, then Ignore Ru…
marcinpsk Apr 27, 2026
41a7c85
fix: update tests to reflect row_class removal
marcinpsk Apr 27, 2026
3029cd3
fix: auto-generate slug when creating platform from sync page (#279)
marcinpsk Apr 28, 2026
cc40f2a
Revert "fix: auto-generate slug when creating platform from sync page…
marcinpsk Apr 28, 2026
120dd00
fix: generate slug when creating Platform via CreateAndAssignPlatform…
marcinpsk Apr 28, 2026
ab284dc
test: assert Platform constructor receives slug in CreateAndAssignPla…
marcinpsk Apr 28, 2026
4d21c55
fix: generate slug when creating Platform via CreateAndAssignPlatform…
marcinpsk Apr 28, 2026
ff76ea1
test: assert Platform constructor receives slug in CreateAndAssignPla…
marcinpsk Apr 28, 2026
7524a16
fix: wrap OOB row in table to survive HTMX HTML parsing
marcinpsk Apr 28, 2026
5edcaed
fix(imports): add HTTP status codes, remove redundant full_clean, fix…
marcinpsk Apr 28, 2026
385d60c
fix(js): extract JSON error message in delete-interfaces handler; gua…
marcinpsk Apr 29, 2026
3fc09bf
refactor(js): extract fetchErrorMessage() helper to unify fetch error…
marcinpsk Apr 29, 2026
d89852d
feat: exact-name-first platform lookup; optional mapping on platform …
marcinpsk Apr 30, 2026
09ca860
fix(pr#50): address CR feedback on AddDeviceTypeMapping form and plat…
marcinpsk Apr 30, 2026
08d78e1
fix(pr#50): isolate PlatformMapping save; ignore stale autocomplete r…
marcinpsk Apr 30, 2026
cb9f923
fix(pr#50): check add_platformmapping permission when create_mapping …
marcinpsk May 1, 2026
ce74bd1
Merge branch 'main' into pr/inventory-core
marcinpsk May 1, 2026
7880f53
fix: address CodeQL security scan findings
marcinpsk May 4, 2026
3c185f7
revert: remove workflow permissions additions (tracked separately)
marcinpsk May 5, 2026
11d4b32
Fix PR review findings: available_roles, CSRF, test quality
marcinpsk May 5, 2026
cdccd3b
Fix PR #58 review findings (batch 2)
marcinpsk May 5, 2026
334ad0d
Fix PR #58 review findings (batch 3)
marcinpsk May 5, 2026
23d4ad6
Fix #59–#62: YAML anchor, DynamicModelChoiceField, ToggleColumn, writ…
marcinpsk May 5, 2026
7162e99
Merge branch 'bonzo81:master' into main
marcinpsk May 5, 2026
4fe7830
Merge branch 'main' into pr/inventory-core
marcinpsk May 5, 2026
0a3f98f
Fix PR #63 review findings: ordering, error handling, modal title, cl…
marcinpsk May 5, 2026
27412d9
Fix replacement template validation and deterministic bay lookup
marcinpsk May 5, 2026
c253af4
Fix wildcard constraint, ambiguity message, and scoped permissions
marcinpsk May 5, 2026
c878e89
devcontainer: restore full debug output in codespaces-configuration.py
marcinpsk May 5, 2026
c869d81
fix(migration): add preflight dedup before wildcard UniqueConstraint
marcinpsk May 5, 2026
917f504
fix: remove dead check_match, close TOCTOU race, fix migration db alias
marcinpsk May 5, 2026
6409609
fix: guard symmetric delete race in AddDeviceTypeMappingView
marcinpsk May 5, 2026
3bfb51c
fix: catch IntegrityError on concurrent create in AddDeviceTypeMappin…
marcinpsk May 6, 2026
52571a1
fix: inject hx-swap-oob on device row in AddDeviceTypeMappingView res…
marcinpsk May 6, 2026
188b0bc
fix: use int:device_id converter on all device-import URL patterns
marcinpsk May 6, 2026
664f5e9
fix: suppress false-positive CodeQL XSS on AddDeviceTypeMappingView r…
marcinpsk May 7, 2026
6ba8308
fix: use format_html + mark_safe to clear CodeQL XSS on AddDeviceType…
marcinpsk May 7, 2026
b39e07e
fix: skip change-permission escalation in concurrent-create no-op path
marcinpsk May 7, 2026
1cf871d
Merge pull request #282 from marcinpsk/fix/platform-slug
bonzo81 May 7, 2026
96a89e1
docs: clarify mark_safe is a trust assertion, not a sanitizer
marcinpsk May 7, 2026
53cbf3a
feat: add VC-aware module sync
bonzo81 May 7, 2026
e731415
test: align VC module sync expectations
bonzo81 May 7, 2026
216fb84
fix: use all ancestor names as bay-mapping candidates
marcinpsk May 7, 2026
ac7e5c5
Revert "fix: use all ancestor names as bay-mapping candidates"
marcinpsk May 7, 2026
03caca0
test: add prod-shape WS-X4908 bay-matching coverage
marcinpsk May 7, 2026
ef6d269
fix: bail _match_bay_by_position on non-container scaffolding
marcinpsk May 7, 2026
2c839f3
fix: restrict serial_matches_device rule to chassis-level entries
marcinpsk May 7, 2026
d5e493e
fix: class-aware positional fallback + model gap warnings
marcinpsk May 8, 2026
be5f175
feat: ModuleBayMapping suggestions + Add Mapping button on No Bay rows
marcinpsk May 8, 2026
0adcc81
fix: address valid code-review findings
marcinpsk May 8, 2026
873e66d
feat: remove {module} conflict warning, add Generic manufacturer fall…
marcinpsk May 8, 2026
1587c7b
fix: replace {module} conflict tooltip with Name Conflict status badg…
marcinpsk May 8, 2026
74e37df
feat: show conflict reason as tooltip on Name Conflict badge
marcinpsk May 8, 2026
c96be2e
fix: re-apply Name Conflict status after _apply_installed_status
marcinpsk May 8, 2026
d98354c
feat: fix Name Conflict tooltip style and add 'Add Mapping' for No Ty…
marcinpsk May 8, 2026
6cccf1e
fix: remove has_nested_name_conflict — obsolete since NetBox 4.5.5 si…
marcinpsk May 8, 2026
51202ca
Revert "fix: remove has_nested_name_conflict — obsolete since NetBox …
marcinpsk May 8, 2026
1166c40
feat: carrier auto-install rules + vendor-scoped ModuleBayMapping + m…
marcinpsk May 9, 2026
91d81fe
fix: bay-mapping suggestions for integrated children and descr-encode…
marcinpsk May 9, 2026
4c6030b
fix: address CodeRabbit review findings (small fixes)
marcinpsk May 9, 2026
4f8dc88
contrib: vendor-scope generic mapping examples (#73)
marcinpsk May 9, 2026
5219c2c
test/js: minor housekeeping nitpicks (#74)
marcinpsk May 9, 2026
13fc72a
docs: clarify ModuleTypeMapping ambiguity asymmetry (#72)
marcinpsk May 9, 2026
e24bfea
refactor: convert module mismatch modal forms to HTMX (#70)
marcinpsk May 9, 2026
6a3f577
fix(db): tighten uniqueness on nullable manufacturer FKs (#71)
marcinpsk May 10, 2026
7f02cad
Suggest descr-anchored bay mapping for fan/PSU rows whose name is jus…
marcinpsk May 10, 2026
d2df39c
Scope ModuleTypeMapping by manufacturer + fix PlatformMapping ambiguo…
marcinpsk May 10, 2026
1af01cd
Fail-closed Generic ModuleType fallback + CodeRabbit nitpicks
marcinpsk May 10, 2026
fe76d4b
Merge branch 'develop' into pr/inventory-core
marcinpsk May 10, 2026
947ff74
PR #67 4th-pass review fixes (CodeRabbit + Copilot)
marcinpsk May 10, 2026
d0809b4
Add Bay Template QoL: inline modal for missing ModuleBayTemplate
marcinpsk May 11, 2026
9ddd284
Address PR #67 5th-pass review comments
marcinpsk May 11, 2026
4fd7111
Add ModuleBayMapping checkbox to Add-Bay-Template modal
marcinpsk May 11, 2026
384bf55
Offer regex ModuleBayMapping when bay name skeleton matches
marcinpsk May 11, 2026
4a6b0b7
Allow regex bay mapping when libre/NetBox skeletons differ
marcinpsk May 11, 2026
ea3473c
Render bay-mapping preview via DOM nodes, not innerHTML
marcinpsk May 11, 2026
c8d737d
Address PR #67 review pass 6: perms + safe-string fixes
marcinpsk May 11, 2026
1795a8f
Instantiate ModuleBayTemplate onto existing devices/modules
marcinpsk May 11, 2026
44a7961
Squash inventory-core migrations 0010-0015 into a single 0010
marcinpsk May 12, 2026
4a28014
Fix permission gate ordering in SingleModuleVerifyView.post()
marcinpsk May 12, 2026
150a6f4
fix(migrations): lower 0010 external deps to NetBox 4.2 floor
marcinpsk May 13, 2026
a193954
fix(import): guard VirtualMachine.cluster access (#284)
marcinpsk May 13, 2026
c5a5f13
Unify platform-create modal & fix conflict-action error UX
marcinpsk May 16, 2026
2afd7d2
Don't gate librenms_id migration on unrelated validation errors
marcinpsk May 16, 2026
32d52fa
Extend htmx error toast to remaining modal endpoints; update tests
marcinpsk May 16, 2026
56e610b
fix(pr-review): address CodeRabbit feedback batch
marcinpsk May 16, 2026
26771db
fix(pr-review): address 2 new CodeRabbit findings
marcinpsk May 16, 2026
5769bf9
Fix UpdateDevicePlatformView to resolve platform via PlatformMapping
marcinpsk May 16, 2026
846188a
Fix import modal platform row: show Not set + sync for existing devic…
marcinpsk May 16, 2026
01a2f92
fix(pr-review): address 4 CodeRabbit findings
marcinpsk May 16, 2026
c0d17de
fix: format_html no-args TypeError in InventoryIgnoreRuleTable
marcinpsk May 17, 2026
b7968c9
fix(migration): match seeded InventoryIgnoreRules on full signature
marcinpsk May 17, 2026
7eb7926
fix(sync): abort stale verify-module fetches before issuing a new one
marcinpsk May 19, 2026
3d8469b
fix(contrib): anchor the two Nokia transceiver bay regex patterns
marcinpsk May 19, 2026
d5b5575
Fix four CodeRabbit review findings
marcinpsk May 19, 2026
c1f2598
Fix broken tests and PlatformMapping savepoint race condition
marcinpsk May 19, 2026
0118f84
Introduce _parse_request_json helper; guard all json.loads in devices.py
marcinpsk May 19, 2026
0269cb0
Move _parse_request_json to mixins; guard cables_view; fix weak tests
marcinpsk May 19, 2026
e77592f
Rename _parse_request_json -> parse_request_json (make public)
marcinpsk May 19, 2026
6d92824
test: strengthen htmx error-path assertions and align names
marcinpsk May 19, 2026
c9ea0d9
fix: address five CodeRabbit findings from PR #288
marcinpsk May 19, 2026
11e5805
fix(forms): drop legacy poller-group cache fallback + add response-sh…
marcinpsk May 19, 2026
331a336
Merge pull request #261 from marcinpsk/pr/inventory-core
bonzo81 May 22, 2026
3de5c61
Merge pull request #287 from marcinpsk/fix/vm-cluster-none-284
bonzo81 May 22, 2026
d7d9961
fix(interfaces): prefer port_id identity and avoid unsafe reassignment
bonzo81 May 12, 2026
abfcd1c
feat(modules): align install flow with interface identity and bay mat…
bonzo81 May 12, 2026
c4a5085
test(modules): add regression coverage for install, matching, and ide…
bonzo81 May 12, 2026
16e8f14
fix(modules): refine bay matching and interface updates
bonzo81 May 22, 2026
7acf09f
fix(template): fix platform modal not rendering on Django 6
marcinpsk May 23, 2026
2c3c3da
fix(template): guard create-platform modal to device objects only
marcinpsk May 23, 2026
76e6362
fix(modules): tighten binding coverage
bonzo81 May 25, 2026
d931914
fix(modules): avoid regex backtracking in label parsing
bonzo81 May 25, 2026
715c6f0
fix(interfaces): ignore duplicate librenms ids in preview
bonzo81 May 25, 2026
8807ffb
fix(modules): warn on partial port metadata failures
bonzo81 May 25, 2026
ac3fb42
docs: document module sync, mapping rules and new features from pr/in…
marcinpsk May 17, 2026
8dd5ea8
docs: replace screenshots with dark mode versions, update image refer…
marcinpsk May 17, 2026
59132c7
docs: reorganize mapping screenshots into subdirectories
marcinpsk May 17, 2026
4fafaf2
docs(mapping_rules): use American spelling consistently
marcinpsk May 19, 2026
61527e5
docs(mapping_rules): satisfy MD031/MD040 on fenced code blocks
marcinpsk May 19, 2026
b2a8c10
docs(mapping_rules): correct Device Type matching description
marcinpsk May 19, 2026
75734f9
docs: correct Platform matching order and ENTITY-MIB scope
marcinpsk May 19, 2026
f1128c8
fix(modules): pass interface permission to verify rows
bonzo81 May 25, 2026
b124d12
fix(modules): adopt interfaces during replace
bonzo81 May 25, 2026
649cc67
docs(module_sync): correct carrier button name to "Install Carrier"
marcinpsk May 25, 2026
6cafe17
Extract stored-only LibreNMS ID helper
bonzo81 May 26, 2026
16cbcbf
Use stored interface IDs in module sync
bonzo81 May 26, 2026
2ad12ad
Adopt template interfaces for installed modules
bonzo81 May 26, 2026
a26d696
Clean up module interface binding follow-ups
bonzo81 May 26, 2026
572cd9d
Build module interface indexes in one pass
bonzo81 May 26, 2026
d217c8c
Tighten cached interface coverage assertions
bonzo81 May 26, 2026
c7f4764
Update README.md
marcinpsk May 26, 2026
18df43c
Share VC-aware module template interface naming
bonzo81 May 27, 2026
f5d6c34
feat(modules): add predict_module_interface_names extension signal
marcinpsk May 27, 2026
b0bd16b
feat(modules): add "Report VC issue" diagnostic for unsupported vendo…
marcinpsk May 27, 2026
882e6f0
fix(modules): review fixes for VC report diagnostic + e2e coverage
marcinpsk May 27, 2026
00341c2
feat(utils): create single normalize_librenms_port_id function to uti…
bonzo81 May 28, 2026
0178c80
Apply formatting-only sync test cleanups
bonzo81 May 28, 2026
814ea64
Keep module tree prefixes on one line
bonzo81 May 28, 2026
bf0faf7
Merge branch 'feat/module-sync-followup' into feat/module-interface-n…
marcinpsk May 28, 2026
fc199f8
Align install bay matching with table-side normalization
bonzo81 May 29, 2026
3c4bb3f
Merge pull request #296 from bonzo81/feat/module-sync-followup
bonzo81 May 29, 2026
814a6e5
Merge branch 'develop' into fix/platform-modal-django6
marcinpsk May 29, 2026
5d572e7
Merge branch 'develop' into docs/pr-inventory-core-docs
marcinpsk May 29, 2026
1b3487f
Merge pull request #294 from marcinpsk/fix/platform-modal-django6
bonzo81 May 29, 2026
61dd15e
test: tighten last-receiver-wins assertion to == ["second"]
marcinpsk May 29, 2026
708c88d
fix(modules): don't render 'No matching bay' on Integrated rows
May 29, 2026
66c72cb
Fix device location showing as dict on sync page (#280)
bonzo81 May 29, 2026
01a6129
Reference LibreNMS 26.5.0 and list location dict keys in comment
bonzo81 May 29, 2026
29b3e2d
Merge pull request #301 from bonzo81/fix/device-location-dict-280
bonzo81 May 29, 2026
919b7f8
Merge pull request #300 from marcinpsk/fix/module-bay-integrated-rows
bonzo81 Jun 1, 2026
0d746a7
feat: UI improvements extracted from oob-sync
marcinpsk May 25, 2026
0d71995
fix(template): close platform-row if and make new-import mapping form…
marcinpsk May 25, 2026
88635b4
fix(AddPlatformMappingView): close TOCTOU window with select_for_update
marcinpsk May 26, 2026
2bc4457
fix(AddPlatformMappingView): use _htmx_error_response and reject "-" OS
marcinpsk May 27, 2026
b72ee93
fix(ui): expose platform-mapping form in existing-device branches
marcinpsk May 31, 2026
7d7be71
fix(ui): guard against duplicate PlatformMapping rows with proper row…
marcinpsk May 31, 2026
517cc95
ui(platform): compact platform cell with a single edit icon -> combin…
marcinpsk May 31, 2026
55509aa
fix(ui): use {% comment %} in _platform_manage_icon (multi-line {# #}…
marcinpsk May 31, 2026
6020daa
test(templates): guard against multi-line {# #} comments leaking as text
marcinpsk May 31, 2026
abf769b
fix(import): forward server_key from mapping forms; use logger.exception
marcinpsk Jun 1, 2026
847e274
feat(ipam): add auto-create IPAM on device/VM import
marcinpsk May 31, 2026
eeb9099
fix(ip_helpers): wrap create() in nested savepoint to avoid poisoning…
marcinpsk May 31, 2026
ee95c05
fix: duplicate PlatformMapping guard and expose VM created_ips in bul…
marcinpsk May 31, 2026
506c40d
fix(ipam): address PR #84 review — server_key in HTMX mapping forms, …
marcinpsk May 31, 2026
4bced09
refactor(ipam): remove generic auto-create-IPAM-on-import feature
marcinpsk May 31, 2026
81ac570
feat(ipam): set Primary IP from LibreNMS mgmt IP on the IP-sync tab
marcinpsk May 31, 2026
a48ff0d
ui(ipam): rename toggle label to 'Set Primary IP'
marcinpsk May 31, 2026
dd0c621
feat(ipam): auto-select the management-IP row when 'Set Primary IP' i…
marcinpsk May 31, 2026
8983a22
fix(ipam): surface IP-sync errors and warn when Primary IP has no int…
marcinpsk May 31, 2026
0c17b06
fix(ipam): check response.ok when persisting the Set-Primary-IP toggl…
marcinpsk May 31, 2026
c7acffa
fix(ip-sync): scope existing-IP lookup to the target VRF
marcinpsk Jun 1, 2026
3328e77
Merge pull request #288 from marcinpsk/docs/pr-inventory-core-docs
bonzo81 Jun 1, 2026
6b59ac6
Merge pull request #303 from marcinpsk/feat/ipam
bonzo81 Jun 1, 2026
00ea133
ci: restrict GITHUB_TOKEN permissions in workflows
bonzo81 Jun 2, 2026
e7cfaa9
fix: localise open-redirect guard to redirect sink
bonzo81 Jun 2, 2026
6be6068
fix: avoid exposing exception details in IP address sync responses
bonzo81 Jun 2, 2026
09f31e8
Merge pull request #304 from bonzo81/security/workflow-token-permissions
bonzo81 Jun 2, 2026
4778786
fix: use positive-guard pattern for redirect validation
bonzo81 Jun 2, 2026
09c7bb1
Merge pull request #305 from bonzo81/security/fix-open-redirect
bonzo81 Jun 2, 2026
bfa903d
Merge pull request #306 from bonzo81/security/fix-stack-trace-exposure
bonzo81 Jun 2, 2026
69d5303
fix(module-hook): isolate signal receivers + log instantiate failures
marcinpsk Jun 2, 2026
c151c1c
test(module-hook): assert isolated receiver failure is logged
marcinpsk Jun 2, 2026
09afc89
Merge pull request #298 from marcinpsk/feat/module-interface-name-pre…
bonzo81 Jun 5, 2026
b324e3a
docs: review and fill gaps for v0.4.7 release
bonzo81 Jun 5, 2026
e6def35
Merge pull request #307 from bonzo81/docs/v0.4.7-review
bonzo81 Jun 5, 2026
a0d6d5c
Bump version to 0.4.7 and update changelog
bonzo81 Jun 5, 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
2 changes: 2 additions & 0 deletions .devcontainer/config/codespaces-configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
"127.0.0.1",
"*",
]
# Development environment — logging config values is an accepted tradeoff here.
# CodeQL alert for this is dismissed intentionally.
Comment on lines +22 to +23

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Avoid codifying a security-alert dismissal without compensating controls.

These comments normalise ignoring the alert, but the file still uses ALLOWED_HOSTS = ["*"]. Even in dev containers, that broad host policy is a risky default and easy to propagate accidentally.

Suggested hardening
@@
-    ALLOWED_HOSTS = [
-        f"{codespace_name}-8000.{port_domain}",
-        "localhost",
-        "127.0.0.1",
-        "*",
-    ]
-    # Development environment — logging config values is an accepted tradeoff here.
-    # CodeQL alert for this is dismissed intentionally.
+    ALLOWED_HOSTS = [
+        f"{codespace_name}-8000.{port_domain}",
+        "localhost",
+        "127.0.0.1",
+    ]
+    # Development environment: keep diagnostics, but avoid broad host wildcards.

print(f"🔗 Codespaces detected: {codespace_name}")
print(f"🔒 CSRF Trusted Origins: {CSRF_TRUSTED_ORIGINS}")
print(f"🌐 Allowed Hosts: {ALLOWED_HOSTS}")
Expand Down
26 changes: 25 additions & 1 deletion .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
> - [frontend.instructions.md](instructions/frontend.instructions.md) – applies to templates and static files
> - [background-jobs.instructions.md](instructions/background-jobs.instructions.md) – applies to `jobs.py`, import views, and import utilities
> - [sync.instructions.md](instructions/sync.instructions.md) – applies to sync views, base views, tables, and sync JS
> - [release.instructions.md](instructions/release.instructions.md) – applies to changelog, pyproject.toml, and `__init__.py` version bumps

## Architecture & Key Modules
- Plugin hooks into NetBox (Django 5) under `netbox_librenms_plugin/`; respect NetBox plugin APIs (`navigation.py`, `urls.py`, `api/`).
Expand Down Expand Up @@ -62,13 +63,36 @@
- `_get_safe_redirect_url(request)` validates referrer URLs to prevent open-redirect attacks.

### Permission Helpers for Background Jobs
- Background jobs run outside view context and cannot use view mixins. Use standalone helpers from `import_utils.py` (`check_user_permissions`, `require_permissions`). See `background-jobs.instructions.md` for details.
- Background jobs run outside view context and cannot use view mixins. Use standalone helpers from `import_utils/permissions.py` (`check_user_permissions`, `require_permissions`). See `background-jobs.instructions.md` for details.

### API & Navigation Permissions
- API endpoints use `LibreNMSPluginPermission` class in `api/views.py` (GET=view, others=change).
- Navigation menu (`navigation.py`) has 3 groups: **Settings** (Plugin Settings, Interface Mappings), **Import** (LibreNMS Import), **Status Check** (Site & Location Sync, Device Status, VM Status). All items use `permissions=[PERM_VIEW_PLUGIN]`.
- **Background job polling requires superuser** — non-superusers fall back to synchronous mode. See `background-jobs.instructions.md` for details.

## CodeQL & Security Patterns

### Clearing CodeQL `py/reflected-xss` false positives
When a view builds an `HttpResponse` from Django-template-rendered HTML (decoded via `.content.decode()`), CodeQL traces `request → template-render → HttpResponse` as reflected XSS even though Django templates auto-escape all user values.

**Correct fix:** use `format_html()` to compose the envelope and `mark_safe()` as a **trust assertion** on the inner HTML — CodeQL's Django taint model recognises this pattern and stops tracking the taint:

```python
from django.utils.html import format_html
from django.utils.safestring import mark_safe

modal_html = some_view.get(request, pk).content.decode("utf-8")
oob = format_html('<div id="target" hx-swap-oob="innerHTML">{}</div>', mark_safe(modal_html))
return HttpResponse(oob, content_type="text/html")
```

> **Important:** `mark_safe()` is a trust assertion, not a sanitizer — it tells Django "I guarantee this string is already safe HTML." Only use it when `modal_html` comes from a server-rendered Django view (whose templates auto-escape all user values). Never pass untrusted user input to `mark_safe()` — that would introduce real XSS.

**Do NOT** use `# lgtm[py/reflected-xss]` — that is LGTM.com legacy syntax and is **not** honoured by GitHub's modern CodeQL Action.

### URL converters
Always use `<int:pk>` (not `<str:pk>`) for numeric IDs in URL patterns. Django's `<int:>` converter auto-validates and returns 404 for non-integer values, eliminating the URL-parameter taint source that CodeQL otherwise flags.

## When in Doubt
- Check docs in `docs/development/` for structure, view inheritance, mixins, and template conventions before introducing new patterns.
- Review the existing sync views (e.g., `views/sync/interfaces.py`) as reference implementations for data flow and caching patterns.
Expand Down
18 changes: 10 additions & 8 deletions .github/instructions/background-jobs.instructions.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
applyTo: "**/jobs.py,**/views/imports/**,**/import_utils.py,**/import_validation_helpers.py"
applyTo: "**/jobs.py,**/views/imports/**,**/import_utils/**,**/import_validation_helpers.py"
description: Background job architecture, import workflow, and task management patterns
---

Expand Down Expand Up @@ -69,13 +69,15 @@ Filter fields: `librenms_location`, `librenms_type`, `librenms_os`, `librenms_ho
- **`DeviceVCDetailsView`** (GET) — renders VC member details via `htmx/device_vc_details.html`.
- **`DeviceRoleUpdateView`**, **`DeviceClusterUpdateView`**, **`DeviceRackUpdateView`** (POST) — per-device dropdown updates. Apply selection to validation state and return re-rendered row via `render_device_row()`.

## Key Import Utilities (`import_utils.py`)
- `process_device_filters(filters, ...)` — fetches and validates devices from LibreNMS, returns list.
- `validate_device_for_import(device, ...)` — core validation function, produces validation state dict.
- `bulk_import_devices_shared(devices, user, ...)` — shared implementation between sync and background import.
- `bulk_import_vms(vm_imports, user, ...)` — VM import implementation.
- `fetch_device_with_cache(device_id, ...)` — retrieves/caches individual device data.
- Cache key functions: `get_validated_device_cache_key()`, `get_cache_metadata_key()`, `get_active_cached_searches()`, `get_import_device_cache_key()`.
## Key Import Utilities (`import_utils/` package)
`import_utils/` is a package; the `__init__.py` re-exports key functions so callers can still use `from import_utils import ...`.

- `filters.py` — `process_device_filters(filters, ...)`, `fetch_device_with_cache(device_id, ...)`.
- `device_operations.py` — `validate_device_for_import(device, ...)`, `bulk_import_devices_shared(devices, user, ...)`.
- `vm_operations.py` — `bulk_import_vms(vm_imports, user, ...)`.
- `cache.py` — `get_validated_device_cache_key()`, `get_cache_metadata_key()`, `get_active_cached_searches()`, `get_import_device_cache_key()`.
- `permissions.py` — `check_user_permissions(user, permissions)`, `require_permissions(user, permissions, action_description)`.
- `virtual_chassis.py` — `create_virtual_chassis_with_members()`, `_sync_module_bay_counter()`.

## Validation Helpers (`import_validation_helpers.py`)
Centralizes validation state mutation used by the role/cluster/rack update views:
Expand Down
3 changes: 2 additions & 1 deletion .github/instructions/frontend.instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@ description: Frontend patterns for templates, HTMX, and static assets
- All HTMX requests and `fetch()` calls must include a CSRF token. The standard pattern is `document.querySelector('[name=csrfmiddlewaretoken]').value` (from a hidden form input). The import JS also uses `getCookie('csrftoken')` as a fallback — prefer the hidden input approach for consistency.

## Modal Implementation
- Modals use Tabler (Bootstrap-like) but **without** `bootstrap.Modal` helpers.
- Modals try Bootstrap 5 native (`bootstrap.Modal`) first, falling back to manual DOM manipulation if unavailable. Both `librenms_sync.js` and `librenms_import.js` follow this pattern via `showModal()`/`hideModal()` helpers.
- Buttons target the `htmx-modal-content` element and JavaScript in `librenms_import.html` toggles the wrapper.
- Do not reintroduce `data-bs-toggle` or duplicate modal IDs.
- The import page uses `ModalManager` class and `filterModalManager` instance—always use this reference in fetch callbacks, not undefined `modalInstance` variables.
- Dismiss handlers (backdrop click, `data-bs-dismiss` buttons) are bound once per element to prevent stacking on repeated `showModal()` calls.

## JavaScript Fetch Patterns
- Always check `response.ok` before processing fetch responses to catch HTTP errors.
Expand Down
149 changes: 149 additions & 0 deletions .github/instructions/release.instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
---
applyTo: "**/changelog.md,**/pyproject.toml,**/__init__.py"
---

# Release Workflow

This describes the standard release process for the NetBox LibreNMS Plugin. Follow these steps exactly when asked to create a new release.

## Branch Strategy

> **Both `develop` and `master` have branch protection.** All changes must go through pull requests — never push directly.

### Standard Flow (used for all releases)

1. **Create `release/X.Y.Z` branch** from develop
2. **Version bump commit** on the release branch
3. **PR `release/X.Y.Z` → develop** (version bump PR)
4. **PR `develop` → master** (release PR) — GitHub will auto-include any commits master is missing
5. **Tag `vX.Y.Z`** on master and create GitHub release
6. **Post-release:** master may now be ahead of develop (e.g. the merge commit). This resolves naturally — step 1 of the next release starts from the current develop, and the release PR (step 4) will reconcile any divergence.

## Files to Update

Three files must be updated in a single commit with message `Bump version to X.Y.Z and update changelog`:

### `netbox_librenms_plugin/__init__.py`
```python
__version__ = "X.Y.Z"
```

### `pyproject.toml`
```toml
version = "X.Y.Z"
```

### `docs/changelog.md`
Prepend a new section at the top (after `# Changelog`). Use the current date in `YYYY-MM-DD` format. Categories used (pick only those that apply):
- `### New Features`
- `### Improvements`
- `### Fixes`
- `### Development`
- `### Documentation`

Example:
```markdown
## X.Y.Z (YYYY-MM-DD)

### Fixes
* Description of fix (#PR_NUMBER)
```

## Version Bump PR (release/X.Y.Z → develop)

**Title:** `Bump version to X.Y.Z and update changelog`

**Body template:**
```markdown
## Summary
Bump version to X.Y.Z and update changelog for release.

## Motivation / Problem
- Maintenance / cleanup

Prepare release X.Y.Z with <brief description of what's included>.

## Scope of Change

- Config / settings
- Docs only

## How Was This Tested?

- Not tested: version bump and changelog only

## Risk Assessment
- No impact on existing users
- No code logic changes

## Backwards Compatibility
- No breaking changes
```

## Release PR (develop → master)

**Title:** `Release X.Y.Z`

**Body template:**
```markdown
## Summary
Release X.Y.Z — merge develop into master for PyPI release.

## Motivation / Problem
- <Bug | Feature | Maintenance / cleanup>

<One-line description of what this release contains, referencing PR numbers.>

## Scope of Change

<List applicable scopes from the PR template>

## Changes
<Bullet list of changes, each referencing PR numbers>
- Bump version to X.Y.Z

## How Was This Tested?

<Summarize testing from the included PRs>

## Risk Assessment
<Brief risk assessment>

## Backwards Compatibility
- No breaking changes
```

## GitHub Release Text

**Tag:** `vX.Y.Z` (create on master)
**Release title:** `vX.Y.Z`

**Body template:**
```markdown
## <Bug Fix Release | Feature Release | Maintenance Release>

<One-paragraph summary of the release. Explain what was wrong and what changed.>

### <Fixes | New Features | Improvements>

- <Change description> (#PR_NUMBER)

> ### Upgrade note
> - <Migration/collectstatic notes, or "No database migrations in this release."> Standard [update process](https://github.com/bonzo81/netbox-librenms-plugin#update) applies.

---

## All Changes
* <commit title> by @<author> in https://github.com/bonzo81/netbox-librenms-plugin/pull/<PR_NUMBER>
```

The "All Changes" section lists only the feature/fix PRs included in the release — not version bump or merge PRs.

## Checklist

- [ ] Version bumped in `__init__.py` and `pyproject.toml`
- [ ] Changelog updated in `docs/changelog.md`
- [ ] Version bump PR merged to develop
- [ ] Release PR merged to master
- [ ] Tag created on master
- [ ] GitHub release published
4 changes: 3 additions & 1 deletion .github/instructions/testing.instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,10 @@ description: Testing patterns and conventions for the NetBox LibreNMS plugin

## Test Coverage by Module
- `librenms_api.py` → `test_librenms_api.py`, `test_librenms_api_helpers.py`
- `import_utils.py`, `import_validation_helpers.py`, `utils.py` → `test_import_utils.py`, `test_import_validation_helpers.py`, `test_utils.py`
- `import_utils/` package (`filters.py`, `device_operations.py`, `vm_operations.py`, `cache.py`, `permissions.py`, `virtual_chassis.py`), `import_validation_helpers.py`, `utils.py` → `test_import_utils.py`, `test_import_validation_helpers.py`, `test_utils.py`
- `jobs.py`, `views/imports/list.py` → `test_background_jobs.py`
- `import_utils/bulk_import.py` → `test_coverage_bulk_import.py`
- Utility helpers (`utils.py` coverage tests) → `test_coverage_utils.py`
- Permission mixins, API permissions, constants → `test_permissions.py`
- VLAN API, mode detection, comparison, sync → `test_vlan_sync.py`
- `VlanAssignmentMixin`, VLAN enrichment → `test_interface_vlan_sync.py`
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/lint-format.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ on:
- master
- develop

permissions:
contents: read

jobs:
format-and-lint:
runs-on: ubuntu-latest
Expand Down
5 changes: 5 additions & 0 deletions .github/workflows/publish-pypi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ on:
tags:
- '*'

# Default to read-only token; the publish-to-pypi job overrides this with the
# id-token: write permission required for PyPI trusted publishing.
permissions:
contents: read

jobs:
build:
name: Build distribution 📦
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ on:
- master
- develop

permissions:
contents: read

jobs:
test-netbox:
runs-on: ubuntu-latest
Expand Down
18 changes: 15 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ The plugin offers the following key features:
### Device Import
Search and import devices from LibreNMS into NetBox with comprehensive validation and control:

- Filter devices by location, type, OS, hostname, or system name
- Filter devices by location, type, OS, hostname, system name, or hardware model
- Validate import prerequisites (Site, Device Type, Device Role)
- Smart matching for Sites, Device Types, and Platforms
- Import as physical Devices or Virtual Machines
Expand All @@ -21,13 +21,23 @@ Search and import devices from LibreNMS into NetBox with comprehensive validatio

See the [Device Import Guide](docs/librenms_import/overview.md) for detailed usage instructions.

### Module / Inventory Sync
Synchronize physical inventory data from LibreNMS (via ENTITY-MIB) to NetBox installed modules:

- Compare LibreNMS inventory items (line-cards, transceivers, fans, PSUs) against NetBox module bays
- Install, update, or skip individual modules directly from the sync table
- Rich mapping system: ModuleTypeMapping, ModuleBayMapping (with regex support), NormalizationRules, InventoryIgnoreRules, CarrierAutoInstallRules
- Virtual Chassis aware — inventory rows distributed across correct VC members

See the [Module Sync Guide](docs/usage_tips/module_sync.md) and [Mapping Rules Guide](docs/usage_tips/mapping_rules.md) for details.

### Device Field Sync
Synchronize device information from LibreNMS to NetBox. The following device fields can be synchronized:

- Device Name (with naming preference support)
- Serial Number (including virtual chassis members)
- Device Type
- Platform
- Platform (via [Platform Mappings](docs/usage_tips/mapping_rules.md#platform-mappings))

### Interface Sync
Pull interface data from Devices and Virtual Machines from LibreNMS into NetBox. The following interface attributes are synchronized:
Expand All @@ -49,6 +59,8 @@ Create cable connection in NetBox from LibreNMS links data.
### IP Address Sync
Create IP address in NetBox from LibreNMS device IP data.

An opt-in **Set Primary IP** toggle on the IP Address Sync tab can also set the device or VM Primary IP.

### VLAN Sync
- Create VLAN objects in NetBox from LibreNMS device VLAN data
- Per-VLAN group assignment with scope-aware auto-selection
Expand All @@ -57,7 +69,7 @@ Create IP address in NetBox from LibreNMS device IP data.

- Add device to LibreNMS from Netbox device page. SNMP v2c and v3 are supported.

### Site & Location Synchronization
### Site & Location Sync
The plugin also supports synchronizing NetBox Sites with LibreNMS locations:
- Compare NetBox sites to LibreNMS location data
- Create LibreNMS locations to match NetBox sites
Expand Down
31 changes: 31 additions & 0 deletions contrib/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Contrib: Example Mapping Files

This directory contains example YAML mapping files for bulk import into the
NetBox LibreNMS Plugin. Each file can be imported via the plugin's bulk import
feature in the NetBox UI.

## How to Import

1. Navigate to the mapping page (e.g., **LibreNMS → Device Type Mappings**)
2. Click the **Import** button (upload icon) in the top right
3. Select **YAML** format
4. Paste the contents of the relevant YAML file
5. Click **Submit**

## Available Mappings

| File | Description |
|------|-------------|
| `interface_type_mappings.yaml` | Maps LibreNMS interface types + speeds to NetBox interface types |
| `device_type_mappings.yaml` | Maps LibreNMS hardware strings to NetBox device types |
| `module_type_mappings.yaml` | Maps LibreNMS inventory model names to NetBox module types (incl. transceivers) |
| `module_bay_mappings.yaml` | Maps LibreNMS inventory container names to NetBox module bay names |
| `normalization_rules.yaml` | Regex-based string normalization applied before module type/bay lookups |
| `inventory_ignore_rules.yaml` | Suppresses phantom ENTITY-MIB entries (e.g. Cisco IOS-XR IDPROM artefacts) |
| `platform_mappings.yaml` | Maps LibreNMS platform strings to NetBox device platforms |

## Customisation

These files are **examples** — adjust values to match the device types, module
types, and interface types defined in your NetBox instance. The `netbox_*`
fields must reference objects that already exist in your NetBox.
Loading