netbox-dlm 0.1.0__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 (41) hide show
  1. netbox_dlm-0.1.0/LICENSE +190 -0
  2. netbox_dlm-0.1.0/PKG-INFO +183 -0
  3. netbox_dlm-0.1.0/README.md +164 -0
  4. netbox_dlm-0.1.0/netbox_dlm/__init__.py +24 -0
  5. netbox_dlm-0.1.0/netbox_dlm/admin.py +72 -0
  6. netbox_dlm-0.1.0/netbox_dlm/api/__init__.py +0 -0
  7. netbox_dlm-0.1.0/netbox_dlm/api/serializers.py +177 -0
  8. netbox_dlm-0.1.0/netbox_dlm/api/urls.py +19 -0
  9. netbox_dlm-0.1.0/netbox_dlm/api/views.py +71 -0
  10. netbox_dlm-0.1.0/netbox_dlm/choices.py +91 -0
  11. netbox_dlm-0.1.0/netbox_dlm/filtersets.py +169 -0
  12. netbox_dlm-0.1.0/netbox_dlm/forms.py +272 -0
  13. netbox_dlm-0.1.0/netbox_dlm/graphql/__init__.py +0 -0
  14. netbox_dlm-0.1.0/netbox_dlm/graphql/schema.py +39 -0
  15. netbox_dlm-0.1.0/netbox_dlm/graphql/types.py +66 -0
  16. netbox_dlm-0.1.0/netbox_dlm/migrations/__init__.py +0 -0
  17. netbox_dlm-0.1.0/netbox_dlm/models.py +392 -0
  18. netbox_dlm-0.1.0/netbox_dlm/navigation.py +123 -0
  19. netbox_dlm-0.1.0/netbox_dlm/scripts.py +126 -0
  20. netbox_dlm-0.1.0/netbox_dlm/tables.py +155 -0
  21. netbox_dlm-0.1.0/netbox_dlm/template_content.py +50 -0
  22. netbox_dlm-0.1.0/netbox_dlm/templates/netbox_dlm/contract.html +48 -0
  23. netbox_dlm-0.1.0/netbox_dlm/templates/netbox_dlm/cve.html +81 -0
  24. netbox_dlm-0.1.0/netbox_dlm/templates/netbox_dlm/device_lifecycle_panel.html +67 -0
  25. netbox_dlm-0.1.0/netbox_dlm/templates/netbox_dlm/devicesoftware.html +22 -0
  26. netbox_dlm-0.1.0/netbox_dlm/templates/netbox_dlm/devicetype_lifecycle_panel.html +35 -0
  27. netbox_dlm-0.1.0/netbox_dlm/templates/netbox_dlm/hardwarenotice.html +32 -0
  28. netbox_dlm-0.1.0/netbox_dlm/templates/netbox_dlm/provider.html +25 -0
  29. netbox_dlm-0.1.0/netbox_dlm/templates/netbox_dlm/softwareimagefile.html +26 -0
  30. netbox_dlm-0.1.0/netbox_dlm/templates/netbox_dlm/softwareversion.html +95 -0
  31. netbox_dlm-0.1.0/netbox_dlm/templates/netbox_dlm/validatedsoftware.html +54 -0
  32. netbox_dlm-0.1.0/netbox_dlm/templates/netbox_dlm/vulnerability.html +23 -0
  33. netbox_dlm-0.1.0/netbox_dlm/urls.py +133 -0
  34. netbox_dlm-0.1.0/netbox_dlm/views.py +293 -0
  35. netbox_dlm-0.1.0/netbox_dlm.egg-info/PKG-INFO +183 -0
  36. netbox_dlm-0.1.0/netbox_dlm.egg-info/SOURCES.txt +39 -0
  37. netbox_dlm-0.1.0/netbox_dlm.egg-info/dependency_links.txt +1 -0
  38. netbox_dlm-0.1.0/netbox_dlm.egg-info/requires.txt +1 -0
  39. netbox_dlm-0.1.0/netbox_dlm.egg-info/top_level.txt +1 -0
  40. netbox_dlm-0.1.0/pyproject.toml +35 -0
  41. netbox_dlm-0.1.0/setup.cfg +4 -0
@@ -0,0 +1,190 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ Copyright 2026 Blake Parker
179
+
180
+ Licensed under the Apache License, Version 2.0 (the "License");
181
+ you may not use this file except in compliance with the License.
182
+ You may obtain a copy of the License at
183
+
184
+ http://www.apache.org/licenses/LICENSE-2.0
185
+
186
+ Unless required by applicable law or agreed to in writing, software
187
+ distributed under the License is distributed on an "AS IS" BASIS,
188
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
189
+ See the License for the specific language governing permissions and
190
+ limitations under the License.
@@ -0,0 +1,183 @@
1
+ Metadata-Version: 2.4
2
+ Name: netbox-dlm
3
+ Version: 0.1.0
4
+ Summary: Device/software/hardware lifecycle management plugin for NetBox
5
+ Author-email: Blake Parker <blake.parker@e280.com>
6
+ License-Expression: Apache-2.0
7
+ Project-URL: Homepage, https://github.com/droolingtaz/netbox-dlm
8
+ Project-URL: Issues, https://github.com/droolingtaz/netbox-dlm/issues
9
+ Classifier: Development Status :: 3 - Alpha
10
+ Classifier: Framework :: Django
11
+ Classifier: Intended Audience :: System Administrators
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Topic :: System :: Networking
14
+ Requires-Python: >=3.10
15
+ Description-Content-Type: text/markdown
16
+ License-File: LICENSE
17
+ Requires-Dist: requests>=2.28
18
+ Dynamic: license-file
19
+
20
+ # netbox-dlm
21
+
22
+ A NetBox plugin for hardware/software lifecycle management — built as a
23
+ real NetBox plugin (Django models, not Custom Objects), since this needs
24
+ background scripts, custom filtersets/API viewsets, and many-to-many
25
+ scoping that Custom Objects doesn't support well.
26
+
27
+ ## What it models
28
+
29
+ - `HardwareNotice` (DeviceType or ModuleType) — EoS/EoL/EoSecurity/EoSW dates
30
+ - `SoftwareVersion` (per Platform)
31
+ - `SoftwareImageFile`
32
+ - `DeviceSoftware` — software actually running on a Device
33
+ - `ValidatedSoftware` — approval rules
34
+ - `Contract`
35
+ - `Provider`
36
+ - `CVE`
37
+ - `Vulnerability`
38
+
39
+ NetBox doesn't have native `SoftwareVersion`/`Contact` core models for
40
+ this, so those are built from scratch here rather than reused.
41
+
42
+ Reports are handled as **on-demand Scripts** (`scripts.py`) rather than
43
+ stored "*Result" models — `CheckHardwareNotices` and `RunSoftwareValidation`
44
+ compute compliance live against current data. This is a deliberate scope
45
+ simplification; add stored result models later as ordinary `NetBoxModel`s
46
+ if you want historical trending of compliance over time.
47
+
48
+ ## Package layout
49
+
50
+ ```
51
+ netbox_dlm/
52
+ ├── __init__.py # PluginConfig
53
+ ├── models.py # Provider, Contract, HardwareNotice, SoftwareVersion,
54
+ │ # SoftwareImageFile, DeviceSoftware, ValidatedSoftware,
55
+ │ # CVE, Vulnerability
56
+ ├── choices.py # ChoiceSets
57
+ ├── admin.py # Django admin registrations
58
+ ├── forms.py # NetBoxModelForm / FilterSetForm classes
59
+ ├── tables.py # NetBoxTable classes
60
+ ├── filtersets.py # NetBoxModelFilterSet classes
61
+ ├── views.py # Generic CRUD views
62
+ ├── urls.py # UI URL routing
63
+ ├── navigation.py # Nav menu ("Device Lifecycle")
64
+ ├── template_content.py # Panels injected onto Device/DeviceType pages
65
+ ├── scripts.py # CheckHardwareNotices, RunSoftwareValidation, SyncCVEs
66
+ ├── templates/netbox_dlm/
67
+ │ ├── device_lifecycle_panel.html
68
+ │ └── devicetype_lifecycle_panel.html
69
+ ├── api/
70
+ │ ├── serializers.py
71
+ │ ├── views.py
72
+ │ └── urls.py
73
+ └── migrations/
74
+ └── __init__.py # run `manage.py makemigrations` in your env (see below)
75
+ ```
76
+
77
+ ## Installation
78
+
79
+ 1. Copy `netbox_dlm/` onto your NetBox host inside the same
80
+ Python environment as NetBox, or install it editable via the included
81
+ `pyproject.toml`:
82
+
83
+ ```bash
84
+ pip install -e /path/to/netbox_dlm
85
+ ```
86
+
87
+ 2. Add to `configuration.py`:
88
+
89
+ ```python
90
+ PLUGINS = [
91
+ "netbox_dlm",
92
+ # ... your other plugins
93
+ ]
94
+
95
+ PLUGINS_CONFIG = {
96
+ "netbox_dlm": {
97
+ "nist_api_key": None, # optional, raises NVD API rate limits
98
+ "eos_warning_days": 180,
99
+ },
100
+ }
101
+ ```
102
+
103
+ 3. **Generate and apply migrations against your actual NetBox version** —
104
+ this repo intentionally ships without a pre-built migration, since exact
105
+ field/constraint behavior is sensitive to the NetBox version pinned in
106
+ your venv:
107
+
108
+ ```bash
109
+ cd /opt/netbox/netbox # your NetBox root
110
+ python3 manage.py makemigrations netbox_dlm
111
+ python3 manage.py migrate
112
+ ```
113
+
114
+ 4. Restart NetBox (`systemctl restart netbox netbox-rq` or your equivalent).
115
+ You should see "Device Lifecycle" in the left nav, and Scripts under
116
+ Operations > Scripts grouped by this plugin.
117
+
118
+ 5. If you're serving static files separately behind a reverse proxy, run
119
+ `python manage.py collectstatic --no-input`.
120
+
121
+ ## Using it
122
+
123
+ - **Providers / Contracts** — track who supports what, and which devices a
124
+ contract covers (`Contract.devices` M2M).
125
+ - **Hardware Notices** — one row per `DeviceType` *or* `ModuleType` (not
126
+ both — enforced in `clean()`), with EoS/EoL/EoSecurity/EoSW dates.
127
+ - **Software Versions / Images** — per `Platform`. `DeviceSoftware` is a
128
+ 1:1 to `Device` recording what's actually running (populate this from your
129
+ existing sync tooling — e.g. alongside `aci_netbox_sync` runs, or a Golden
130
+ Config compliance pass).
131
+ - **Validated Software** — approval rules scoped by `device_types`,
132
+ `device_roles`, and/or specific `devices` (M2M). A rule
133
+ with no scope at all applies to any device running that software version.
134
+ `preferred=True` marks the target version for a given scope; `covers_device()`
135
+ and `valid_now` do the compliance-check heavy lifting.
136
+ - **CVE / Vulnerability** — `CVE.affected_software` M2M links a CVE to one or
137
+ more `SoftwareVersion`s; `Vulnerability` narrows that down to (optionally) a
138
+ specific `Device`, with its own `status` workflow (open → mitigated/resolved).
139
+ - **Scripts** (Operations > Scripts > Device Lifecycle Management):
140
+ - `Check Hardware Notices` — flags past-due and upcoming EoS.
141
+ - `Run Software Validation` — flags devices whose recorded software has no
142
+ currently-valid `ValidatedSoftware` rule, or isn't the preferred version.
143
+ - `Sync CVEs from NIST NVD` — placeholder; wire up the actual NVD API 2.0
144
+ HTTP calls once your NetBox host has outbound access to
145
+ `services.nvd.nist.gov`.
146
+
147
+ Device and DeviceType pages get a right-hand panel (via `template_content.py`)
148
+ summarizing running software, compliance status, hardware notice, and open
149
+ vulnerabilities at a glance.
150
+
151
+ ## Testing
152
+
153
+ ```bash
154
+ ./scripts/test-templates.sh
155
+ ```
156
+
157
+ First run clones `netbox-community/netbox` (pinned to the version this
158
+ plugin targets) and builds a venv under `.dev/` (gitignored, ~150MB);
159
+ subsequent runs reuse it. It compiles every template in
160
+ `netbox_dlm/templates/netbox_dlm/` through NetBox's real template engine —
161
+ no database or Redis needed, since template compilation never touches the
162
+ ORM. This catches `TemplateSyntaxError`/`TemplateDoesNotExist` (bad
163
+ `{% load %}`, filters used where a tag was needed, missing includes)
164
+ before they reach a deployed host. It won't catch bugs that only manifest
165
+ at render time against real data (e.g. a table column referencing a model
166
+ attribute that silently resolves to nothing) — there's no substitute for
167
+ exercising the view against a real NetBox + Postgres instance for that.
168
+
169
+ ## What I didn't build (scope cuts, worth knowing about)
170
+
171
+ - **Stored compliance-result models / history** — this plugin computes
172
+ compliance live via scripts rather than persisting result rows.
173
+ Straightforward to add later as another `NetBoxModel` if you want a
174
+ graphable history.
175
+ - **Inventory item lifecycle** — hardware notices are scoped to
176
+ `Module`/`ModuleType` (NetBox's modern equivalent); if you're still
177
+ using NetBox's legacy `InventoryItem` model for non-modular gear, that's a
178
+ straightforward additional FK to add to `HardwareNotice`.
179
+ - **VM software tracking** — `DeviceSoftware` only covers `Device`, not
180
+ `VirtualMachine`. Trivial to mirror if needed.
181
+ - **Automated CVE ingestion** — `SyncCVEs` is a stub; NVD API 2.0
182
+ request/response handling needs to be written against whatever
183
+ auth/rate-limit setup you use.
@@ -0,0 +1,164 @@
1
+ # netbox-dlm
2
+
3
+ A NetBox plugin for hardware/software lifecycle management — built as a
4
+ real NetBox plugin (Django models, not Custom Objects), since this needs
5
+ background scripts, custom filtersets/API viewsets, and many-to-many
6
+ scoping that Custom Objects doesn't support well.
7
+
8
+ ## What it models
9
+
10
+ - `HardwareNotice` (DeviceType or ModuleType) — EoS/EoL/EoSecurity/EoSW dates
11
+ - `SoftwareVersion` (per Platform)
12
+ - `SoftwareImageFile`
13
+ - `DeviceSoftware` — software actually running on a Device
14
+ - `ValidatedSoftware` — approval rules
15
+ - `Contract`
16
+ - `Provider`
17
+ - `CVE`
18
+ - `Vulnerability`
19
+
20
+ NetBox doesn't have native `SoftwareVersion`/`Contact` core models for
21
+ this, so those are built from scratch here rather than reused.
22
+
23
+ Reports are handled as **on-demand Scripts** (`scripts.py`) rather than
24
+ stored "*Result" models — `CheckHardwareNotices` and `RunSoftwareValidation`
25
+ compute compliance live against current data. This is a deliberate scope
26
+ simplification; add stored result models later as ordinary `NetBoxModel`s
27
+ if you want historical trending of compliance over time.
28
+
29
+ ## Package layout
30
+
31
+ ```
32
+ netbox_dlm/
33
+ ├── __init__.py # PluginConfig
34
+ ├── models.py # Provider, Contract, HardwareNotice, SoftwareVersion,
35
+ │ # SoftwareImageFile, DeviceSoftware, ValidatedSoftware,
36
+ │ # CVE, Vulnerability
37
+ ├── choices.py # ChoiceSets
38
+ ├── admin.py # Django admin registrations
39
+ ├── forms.py # NetBoxModelForm / FilterSetForm classes
40
+ ├── tables.py # NetBoxTable classes
41
+ ├── filtersets.py # NetBoxModelFilterSet classes
42
+ ├── views.py # Generic CRUD views
43
+ ├── urls.py # UI URL routing
44
+ ├── navigation.py # Nav menu ("Device Lifecycle")
45
+ ├── template_content.py # Panels injected onto Device/DeviceType pages
46
+ ├── scripts.py # CheckHardwareNotices, RunSoftwareValidation, SyncCVEs
47
+ ├── templates/netbox_dlm/
48
+ │ ├── device_lifecycle_panel.html
49
+ │ └── devicetype_lifecycle_panel.html
50
+ ├── api/
51
+ │ ├── serializers.py
52
+ │ ├── views.py
53
+ │ └── urls.py
54
+ └── migrations/
55
+ └── __init__.py # run `manage.py makemigrations` in your env (see below)
56
+ ```
57
+
58
+ ## Installation
59
+
60
+ 1. Copy `netbox_dlm/` onto your NetBox host inside the same
61
+ Python environment as NetBox, or install it editable via the included
62
+ `pyproject.toml`:
63
+
64
+ ```bash
65
+ pip install -e /path/to/netbox_dlm
66
+ ```
67
+
68
+ 2. Add to `configuration.py`:
69
+
70
+ ```python
71
+ PLUGINS = [
72
+ "netbox_dlm",
73
+ # ... your other plugins
74
+ ]
75
+
76
+ PLUGINS_CONFIG = {
77
+ "netbox_dlm": {
78
+ "nist_api_key": None, # optional, raises NVD API rate limits
79
+ "eos_warning_days": 180,
80
+ },
81
+ }
82
+ ```
83
+
84
+ 3. **Generate and apply migrations against your actual NetBox version** —
85
+ this repo intentionally ships without a pre-built migration, since exact
86
+ field/constraint behavior is sensitive to the NetBox version pinned in
87
+ your venv:
88
+
89
+ ```bash
90
+ cd /opt/netbox/netbox # your NetBox root
91
+ python3 manage.py makemigrations netbox_dlm
92
+ python3 manage.py migrate
93
+ ```
94
+
95
+ 4. Restart NetBox (`systemctl restart netbox netbox-rq` or your equivalent).
96
+ You should see "Device Lifecycle" in the left nav, and Scripts under
97
+ Operations > Scripts grouped by this plugin.
98
+
99
+ 5. If you're serving static files separately behind a reverse proxy, run
100
+ `python manage.py collectstatic --no-input`.
101
+
102
+ ## Using it
103
+
104
+ - **Providers / Contracts** — track who supports what, and which devices a
105
+ contract covers (`Contract.devices` M2M).
106
+ - **Hardware Notices** — one row per `DeviceType` *or* `ModuleType` (not
107
+ both — enforced in `clean()`), with EoS/EoL/EoSecurity/EoSW dates.
108
+ - **Software Versions / Images** — per `Platform`. `DeviceSoftware` is a
109
+ 1:1 to `Device` recording what's actually running (populate this from your
110
+ existing sync tooling — e.g. alongside `aci_netbox_sync` runs, or a Golden
111
+ Config compliance pass).
112
+ - **Validated Software** — approval rules scoped by `device_types`,
113
+ `device_roles`, and/or specific `devices` (M2M). A rule
114
+ with no scope at all applies to any device running that software version.
115
+ `preferred=True` marks the target version for a given scope; `covers_device()`
116
+ and `valid_now` do the compliance-check heavy lifting.
117
+ - **CVE / Vulnerability** — `CVE.affected_software` M2M links a CVE to one or
118
+ more `SoftwareVersion`s; `Vulnerability` narrows that down to (optionally) a
119
+ specific `Device`, with its own `status` workflow (open → mitigated/resolved).
120
+ - **Scripts** (Operations > Scripts > Device Lifecycle Management):
121
+ - `Check Hardware Notices` — flags past-due and upcoming EoS.
122
+ - `Run Software Validation` — flags devices whose recorded software has no
123
+ currently-valid `ValidatedSoftware` rule, or isn't the preferred version.
124
+ - `Sync CVEs from NIST NVD` — placeholder; wire up the actual NVD API 2.0
125
+ HTTP calls once your NetBox host has outbound access to
126
+ `services.nvd.nist.gov`.
127
+
128
+ Device and DeviceType pages get a right-hand panel (via `template_content.py`)
129
+ summarizing running software, compliance status, hardware notice, and open
130
+ vulnerabilities at a glance.
131
+
132
+ ## Testing
133
+
134
+ ```bash
135
+ ./scripts/test-templates.sh
136
+ ```
137
+
138
+ First run clones `netbox-community/netbox` (pinned to the version this
139
+ plugin targets) and builds a venv under `.dev/` (gitignored, ~150MB);
140
+ subsequent runs reuse it. It compiles every template in
141
+ `netbox_dlm/templates/netbox_dlm/` through NetBox's real template engine —
142
+ no database or Redis needed, since template compilation never touches the
143
+ ORM. This catches `TemplateSyntaxError`/`TemplateDoesNotExist` (bad
144
+ `{% load %}`, filters used where a tag was needed, missing includes)
145
+ before they reach a deployed host. It won't catch bugs that only manifest
146
+ at render time against real data (e.g. a table column referencing a model
147
+ attribute that silently resolves to nothing) — there's no substitute for
148
+ exercising the view against a real NetBox + Postgres instance for that.
149
+
150
+ ## What I didn't build (scope cuts, worth knowing about)
151
+
152
+ - **Stored compliance-result models / history** — this plugin computes
153
+ compliance live via scripts rather than persisting result rows.
154
+ Straightforward to add later as another `NetBoxModel` if you want a
155
+ graphable history.
156
+ - **Inventory item lifecycle** — hardware notices are scoped to
157
+ `Module`/`ModuleType` (NetBox's modern equivalent); if you're still
158
+ using NetBox's legacy `InventoryItem` model for non-modular gear, that's a
159
+ straightforward additional FK to add to `HardwareNotice`.
160
+ - **VM software tracking** — `DeviceSoftware` only covers `Device`, not
161
+ `VirtualMachine`. Trivial to mirror if needed.
162
+ - **Automated CVE ingestion** — `SyncCVEs` is a stub; NVD API 2.0
163
+ request/response handling needs to be written against whatever
164
+ auth/rate-limit setup you use.
@@ -0,0 +1,24 @@
1
+ from netbox.plugins import PluginConfig
2
+
3
+
4
+ class DeviceLifecycleConfig(PluginConfig):
5
+ name = "netbox_dlm"
6
+ verbose_name = "Device Lifecycle Management"
7
+ description = (
8
+ "Track hardware end-of-life/end-of-support notices, software versions and "
9
+ "validated-software compliance, CVE/vulnerability exposure, and maintenance "
10
+ "contracts — modeled after Nautobot's Device Lifecycle Management app."
11
+ )
12
+ version = "0.1.0"
13
+ base_url = "device-lifecycle"
14
+ min_version = "4.1.0"
15
+ default_settings = {
16
+ # Set to a NIST NVD API key to raise CVE-lookup rate limits (optional).
17
+ "nist_api_key": None,
18
+ # How many days out a hardware/software EoS date counts as "upcoming"
19
+ # for dashboard highlighting.
20
+ "eos_warning_days": 180,
21
+ }
22
+
23
+
24
+ config = DeviceLifecycleConfig
@@ -0,0 +1,72 @@
1
+ from django.contrib import admin
2
+
3
+ from .models import (
4
+ CVE,
5
+ Contract,
6
+ DeviceSoftware,
7
+ HardwareNotice,
8
+ Provider,
9
+ SoftwareImageFile,
10
+ SoftwareVersion,
11
+ ValidatedSoftware,
12
+ Vulnerability,
13
+ )
14
+
15
+
16
+ @admin.register(Provider)
17
+ class ProviderAdmin(admin.ModelAdmin):
18
+ list_display = ("name", "phone", "email", "portal_url")
19
+ search_fields = ("name", "email")
20
+
21
+
22
+ @admin.register(Contract)
23
+ class ContractAdmin(admin.ModelAdmin):
24
+ list_display = ("name", "provider", "support_level", "start_date", "end_date")
25
+ list_filter = ("provider", "support_level")
26
+ search_fields = ("name", "contract_number")
27
+
28
+
29
+ @admin.register(HardwareNotice)
30
+ class HardwareNoticeAdmin(admin.ModelAdmin):
31
+ list_display = ("__str__", "end_of_sale", "end_of_support", "end_of_security_patches")
32
+ list_filter = ("end_of_support",)
33
+
34
+
35
+ @admin.register(SoftwareVersion)
36
+ class SoftwareVersionAdmin(admin.ModelAdmin):
37
+ list_display = ("__str__", "platform", "version", "release_date", "end_of_support", "long_term_support")
38
+ list_filter = ("platform", "long_term_support")
39
+ search_fields = ("version", "alias")
40
+
41
+
42
+ @admin.register(SoftwareImageFile)
43
+ class SoftwareImageFileAdmin(admin.ModelAdmin):
44
+ list_display = ("file_name", "software_version", "hashing_algorithm", "default_image")
45
+ list_filter = ("hashing_algorithm", "default_image")
46
+ search_fields = ("file_name", "checksum")
47
+
48
+
49
+ @admin.register(DeviceSoftware)
50
+ class DeviceSoftwareAdmin(admin.ModelAdmin):
51
+ list_display = ("device", "software_version", "last_checked")
52
+ search_fields = ("device__name",)
53
+
54
+
55
+ @admin.register(ValidatedSoftware)
56
+ class ValidatedSoftwareAdmin(admin.ModelAdmin):
57
+ list_display = ("software_version", "start", "end", "preferred", "valid_now")
58
+ list_filter = ("preferred",)
59
+
60
+
61
+ @admin.register(CVE)
62
+ class CVEAdmin(admin.ModelAdmin):
63
+ list_display = ("cve_id", "name", "severity", "status", "cvss_score", "published_date")
64
+ list_filter = ("severity", "status")
65
+ search_fields = ("cve_id", "name", "description")
66
+
67
+
68
+ @admin.register(Vulnerability)
69
+ class VulnerabilityAdmin(admin.ModelAdmin):
70
+ list_display = ("cve", "software_version", "device", "status")
71
+ list_filter = ("status",)
72
+ search_fields = ("cve__cve_id", "device__name")
File without changes