netbox-dlm 0.1.0__py3-none-any.whl

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 (36) hide show
  1. netbox_dlm/__init__.py +24 -0
  2. netbox_dlm/admin.py +72 -0
  3. netbox_dlm/api/__init__.py +0 -0
  4. netbox_dlm/api/serializers.py +177 -0
  5. netbox_dlm/api/urls.py +19 -0
  6. netbox_dlm/api/views.py +71 -0
  7. netbox_dlm/choices.py +91 -0
  8. netbox_dlm/filtersets.py +169 -0
  9. netbox_dlm/forms.py +272 -0
  10. netbox_dlm/graphql/__init__.py +0 -0
  11. netbox_dlm/graphql/schema.py +39 -0
  12. netbox_dlm/graphql/types.py +66 -0
  13. netbox_dlm/migrations/__init__.py +0 -0
  14. netbox_dlm/models.py +392 -0
  15. netbox_dlm/navigation.py +123 -0
  16. netbox_dlm/scripts.py +126 -0
  17. netbox_dlm/tables.py +155 -0
  18. netbox_dlm/template_content.py +50 -0
  19. netbox_dlm/templates/netbox_dlm/contract.html +48 -0
  20. netbox_dlm/templates/netbox_dlm/cve.html +81 -0
  21. netbox_dlm/templates/netbox_dlm/device_lifecycle_panel.html +67 -0
  22. netbox_dlm/templates/netbox_dlm/devicesoftware.html +22 -0
  23. netbox_dlm/templates/netbox_dlm/devicetype_lifecycle_panel.html +35 -0
  24. netbox_dlm/templates/netbox_dlm/hardwarenotice.html +32 -0
  25. netbox_dlm/templates/netbox_dlm/provider.html +25 -0
  26. netbox_dlm/templates/netbox_dlm/softwareimagefile.html +26 -0
  27. netbox_dlm/templates/netbox_dlm/softwareversion.html +95 -0
  28. netbox_dlm/templates/netbox_dlm/validatedsoftware.html +54 -0
  29. netbox_dlm/templates/netbox_dlm/vulnerability.html +23 -0
  30. netbox_dlm/urls.py +133 -0
  31. netbox_dlm/views.py +293 -0
  32. netbox_dlm-0.1.0.dist-info/METADATA +183 -0
  33. netbox_dlm-0.1.0.dist-info/RECORD +36 -0
  34. netbox_dlm-0.1.0.dist-info/WHEEL +5 -0
  35. netbox_dlm-0.1.0.dist-info/licenses/LICENSE +190 -0
  36. netbox_dlm-0.1.0.dist-info/top_level.txt +1 -0
netbox_dlm/__init__.py ADDED
@@ -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
netbox_dlm/admin.py ADDED
@@ -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
@@ -0,0 +1,177 @@
1
+ from dcim.api.serializers import (
2
+ DeviceSerializer,
3
+ DeviceRoleSerializer,
4
+ DeviceTypeSerializer,
5
+ ModuleTypeSerializer,
6
+ PlatformSerializer,
7
+ )
8
+ from netbox.api.fields import ChoiceField
9
+ from netbox.api.serializers import NetBoxModelSerializer
10
+ from rest_framework import serializers
11
+
12
+ from ..choices import (
13
+ ContractSupportLevelChoices,
14
+ CVESeverityChoices,
15
+ CVEStatusChoices,
16
+ HashingAlgorithmChoices,
17
+ VulnerabilityStatusChoices,
18
+ )
19
+ from ..models import (
20
+ CVE,
21
+ Contract,
22
+ DeviceSoftware,
23
+ HardwareNotice,
24
+ Provider,
25
+ SoftwareImageFile,
26
+ SoftwareVersion,
27
+ ValidatedSoftware,
28
+ Vulnerability,
29
+ )
30
+
31
+
32
+ class ProviderSerializer(NetBoxModelSerializer):
33
+ url = serializers.HyperlinkedIdentityField(
34
+ view_name="plugins-api:netbox_dlm-api:provider-detail"
35
+ )
36
+
37
+ class Meta:
38
+ model = Provider
39
+ fields = (
40
+ "id", "url", "display", "name", "physical_address", "phone",
41
+ "email", "portal_url", "comments", "tags", "custom_fields",
42
+ "created", "last_updated",
43
+ )
44
+
45
+
46
+ class ContractSerializer(NetBoxModelSerializer):
47
+ url = serializers.HyperlinkedIdentityField(
48
+ view_name="plugins-api:netbox_dlm-api:contract-detail"
49
+ )
50
+ provider = ProviderSerializer(nested=True)
51
+ support_level = ChoiceField(choices=ContractSupportLevelChoices, required=False)
52
+ devices = DeviceSerializer(nested=True, many=True, required=False)
53
+
54
+ class Meta:
55
+ model = Contract
56
+ fields = (
57
+ "id", "url", "display", "provider", "name", "contract_number",
58
+ "start_date", "end_date", "cost", "currency", "support_level",
59
+ "devices", "comments", "tags", "custom_fields", "created", "last_updated",
60
+ )
61
+
62
+
63
+ class HardwareNoticeSerializer(NetBoxModelSerializer):
64
+ url = serializers.HyperlinkedIdentityField(
65
+ view_name="plugins-api:netbox_dlm-api:hardwarenotice-detail"
66
+ )
67
+ device_type = DeviceTypeSerializer(nested=True, required=False, allow_null=True)
68
+ module_type = ModuleTypeSerializer(nested=True, required=False, allow_null=True)
69
+
70
+ class Meta:
71
+ model = HardwareNotice
72
+ fields = (
73
+ "id", "url", "display", "device_type", "module_type", "end_of_sale",
74
+ "end_of_support", "end_of_security_patches", "end_of_sw_releases",
75
+ "documentation_url", "comments", "tags", "custom_fields",
76
+ "created", "last_updated",
77
+ )
78
+
79
+
80
+ class SoftwareVersionSerializer(NetBoxModelSerializer):
81
+ url = serializers.HyperlinkedIdentityField(
82
+ view_name="plugins-api:netbox_dlm-api:softwareversion-detail"
83
+ )
84
+ platform = PlatformSerializer(nested=True)
85
+
86
+ class Meta:
87
+ model = SoftwareVersion
88
+ fields = (
89
+ "id", "url", "display", "platform", "version", "alias",
90
+ "release_date", "end_of_support", "long_term_support",
91
+ "documentation_url", "comments", "tags", "custom_fields",
92
+ "created", "last_updated",
93
+ )
94
+
95
+
96
+ class SoftwareImageFileSerializer(NetBoxModelSerializer):
97
+ url = serializers.HyperlinkedIdentityField(
98
+ view_name="plugins-api:netbox_dlm-api:softwareimagefile-detail"
99
+ )
100
+ software_version = SoftwareVersionSerializer(nested=True)
101
+ hashing_algorithm = ChoiceField(choices=HashingAlgorithmChoices, required=False)
102
+
103
+ class Meta:
104
+ model = SoftwareImageFile
105
+ fields = (
106
+ "id", "url", "display", "software_version", "file_name", "checksum",
107
+ "hashing_algorithm", "file_size", "download_url", "default_image",
108
+ "comments", "tags", "custom_fields", "created", "last_updated",
109
+ )
110
+
111
+
112
+ class DeviceSoftwareSerializer(NetBoxModelSerializer):
113
+ url = serializers.HyperlinkedIdentityField(
114
+ view_name="plugins-api:netbox_dlm-api:devicesoftware-detail"
115
+ )
116
+ device = DeviceSerializer(nested=True)
117
+ software_version = SoftwareVersionSerializer(nested=True)
118
+
119
+ class Meta:
120
+ model = DeviceSoftware
121
+ fields = (
122
+ "id", "url", "display", "device", "software_version", "last_checked",
123
+ "comments", "tags", "custom_fields", "created", "last_updated",
124
+ )
125
+
126
+
127
+ class ValidatedSoftwareSerializer(NetBoxModelSerializer):
128
+ url = serializers.HyperlinkedIdentityField(
129
+ view_name="plugins-api:netbox_dlm-api:validatedsoftware-detail"
130
+ )
131
+ software_version = SoftwareVersionSerializer(nested=True)
132
+ device_types = DeviceTypeSerializer(nested=True, many=True, required=False)
133
+ device_roles = DeviceRoleSerializer(nested=True, many=True, required=False)
134
+ devices = DeviceSerializer(nested=True, many=True, required=False)
135
+
136
+ class Meta:
137
+ model = ValidatedSoftware
138
+ fields = (
139
+ "id", "url", "display", "software_version", "device_types",
140
+ "device_roles", "devices", "start", "end", "preferred",
141
+ "comments", "tags", "custom_fields", "created", "last_updated",
142
+ )
143
+
144
+
145
+ class CVESerializer(NetBoxModelSerializer):
146
+ url = serializers.HyperlinkedIdentityField(
147
+ view_name="plugins-api:netbox_dlm-api:cve-detail"
148
+ )
149
+ status = ChoiceField(choices=CVEStatusChoices, required=False)
150
+ severity = ChoiceField(choices=CVESeverityChoices, required=False)
151
+ affected_software = SoftwareVersionSerializer(nested=True, many=True, required=False)
152
+
153
+ class Meta:
154
+ model = CVE
155
+ fields = (
156
+ "id", "url", "display", "cve_id", "name", "description",
157
+ "published_date", "link", "status", "severity", "cvss_score",
158
+ "cvss_v2_score", "cvss_v3_score", "affected_software", "comments",
159
+ "tags", "custom_fields", "created", "last_updated",
160
+ )
161
+
162
+
163
+ class VulnerabilitySerializer(NetBoxModelSerializer):
164
+ url = serializers.HyperlinkedIdentityField(
165
+ view_name="plugins-api:netbox_dlm-api:vulnerability-detail"
166
+ )
167
+ cve = CVESerializer(nested=True)
168
+ software_version = SoftwareVersionSerializer(nested=True)
169
+ device = DeviceSerializer(nested=True, required=False, allow_null=True)
170
+ status = ChoiceField(choices=VulnerabilityStatusChoices, required=False)
171
+
172
+ class Meta:
173
+ model = Vulnerability
174
+ fields = (
175
+ "id", "url", "display", "cve", "software_version", "device",
176
+ "status", "comments", "tags", "custom_fields", "created", "last_updated",
177
+ )
netbox_dlm/api/urls.py ADDED
@@ -0,0 +1,19 @@
1
+ from netbox.api.routers import NetBoxRouter
2
+
3
+ from . import views
4
+
5
+ app_name = "netbox_dlm-api"
6
+
7
+ router = NetBoxRouter()
8
+
9
+ router.register("providers", views.ProviderViewSet)
10
+ router.register("contracts", views.ContractViewSet)
11
+ router.register("hardware-notices", views.HardwareNoticeViewSet)
12
+ router.register("software-versions", views.SoftwareVersionViewSet)
13
+ router.register("software-images", views.SoftwareImageFileViewSet)
14
+ router.register("device-software", views.DeviceSoftwareViewSet)
15
+ router.register("validated-software", views.ValidatedSoftwareViewSet)
16
+ router.register("cves", views.CVEViewSet)
17
+ router.register("vulnerabilities", views.VulnerabilityViewSet)
18
+
19
+ urlpatterns = router.urls
@@ -0,0 +1,71 @@
1
+ from netbox.api.viewsets import NetBoxModelViewSet
2
+
3
+ from .. import filtersets
4
+ from ..models import (
5
+ CVE,
6
+ Contract,
7
+ DeviceSoftware,
8
+ HardwareNotice,
9
+ Provider,
10
+ SoftwareImageFile,
11
+ SoftwareVersion,
12
+ ValidatedSoftware,
13
+ Vulnerability,
14
+ )
15
+ from . import serializers
16
+
17
+
18
+ class ProviderViewSet(NetBoxModelViewSet):
19
+ queryset = Provider.objects.all()
20
+ serializer_class = serializers.ProviderSerializer
21
+ filterset_class = filtersets.ProviderFilterSet
22
+
23
+
24
+ class ContractViewSet(NetBoxModelViewSet):
25
+ queryset = Contract.objects.prefetch_related("provider", "devices", "tags")
26
+ serializer_class = serializers.ContractSerializer
27
+ filterset_class = filtersets.ContractFilterSet
28
+
29
+
30
+ class HardwareNoticeViewSet(NetBoxModelViewSet):
31
+ queryset = HardwareNotice.objects.prefetch_related("device_type", "module_type", "tags")
32
+ serializer_class = serializers.HardwareNoticeSerializer
33
+ filterset_class = filtersets.HardwareNoticeFilterSet
34
+
35
+
36
+ class SoftwareVersionViewSet(NetBoxModelViewSet):
37
+ queryset = SoftwareVersion.objects.prefetch_related("platform", "tags")
38
+ serializer_class = serializers.SoftwareVersionSerializer
39
+ filterset_class = filtersets.SoftwareVersionFilterSet
40
+
41
+
42
+ class SoftwareImageFileViewSet(NetBoxModelViewSet):
43
+ queryset = SoftwareImageFile.objects.prefetch_related("software_version", "tags")
44
+ serializer_class = serializers.SoftwareImageFileSerializer
45
+ filterset_class = filtersets.SoftwareImageFileFilterSet
46
+
47
+
48
+ class DeviceSoftwareViewSet(NetBoxModelViewSet):
49
+ queryset = DeviceSoftware.objects.prefetch_related("device", "software_version", "tags")
50
+ serializer_class = serializers.DeviceSoftwareSerializer
51
+ filterset_class = filtersets.DeviceSoftwareFilterSet
52
+
53
+
54
+ class ValidatedSoftwareViewSet(NetBoxModelViewSet):
55
+ queryset = ValidatedSoftware.objects.prefetch_related(
56
+ "software_version", "device_types", "device_roles", "devices", "tags"
57
+ )
58
+ serializer_class = serializers.ValidatedSoftwareSerializer
59
+ filterset_class = filtersets.ValidatedSoftwareFilterSet
60
+
61
+
62
+ class CVEViewSet(NetBoxModelViewSet):
63
+ queryset = CVE.objects.prefetch_related("affected_software", "tags")
64
+ serializer_class = serializers.CVESerializer
65
+ filterset_class = filtersets.CVEFilterSet
66
+
67
+
68
+ class VulnerabilityViewSet(NetBoxModelViewSet):
69
+ queryset = Vulnerability.objects.prefetch_related("cve", "software_version", "device", "tags")
70
+ serializer_class = serializers.VulnerabilitySerializer
71
+ filterset_class = filtersets.VulnerabilityFilterSet
netbox_dlm/choices.py ADDED
@@ -0,0 +1,91 @@
1
+ from utilities.choices import ChoiceSet
2
+
3
+
4
+ class HashingAlgorithmChoices(ChoiceSet):
5
+ key = "SoftwareImageFile.hashing_algorithm"
6
+
7
+ MD5 = "md5"
8
+ SHA1 = "sha1"
9
+ SHA256 = "sha256"
10
+ SHA512 = "sha512"
11
+
12
+ CHOICES = [
13
+ (MD5, "MD5"),
14
+ (SHA1, "SHA1"),
15
+ (SHA256, "SHA256"),
16
+ (SHA512, "SHA512"),
17
+ ]
18
+
19
+
20
+ class ContractSupportLevelChoices(ChoiceSet):
21
+ key = "Contract.support_level"
22
+
23
+ BASIC = "basic"
24
+ STANDARD = "standard"
25
+ ENHANCED = "enhanced"
26
+ PREMIUM = "premium"
27
+ NEXT_BUSINESS_DAY = "next_business_day"
28
+ FOUR_HOUR = "four_hour_onsite"
29
+ NONE = "none"
30
+
31
+ CHOICES = [
32
+ (BASIC, "Basic"),
33
+ (STANDARD, "Standard"),
34
+ (ENHANCED, "Enhanced"),
35
+ (PREMIUM, "Premium"),
36
+ (NEXT_BUSINESS_DAY, "Next Business Day"),
37
+ (FOUR_HOUR, "4-Hour Onsite"),
38
+ (NONE, "None"),
39
+ ]
40
+
41
+
42
+ class CVESeverityChoices(ChoiceSet):
43
+ key = "CVE.severity"
44
+
45
+ NONE = "none"
46
+ LOW = "low"
47
+ MEDIUM = "medium"
48
+ HIGH = "high"
49
+ CRITICAL = "critical"
50
+
51
+ CHOICES = [
52
+ (NONE, "None", "gray"),
53
+ (LOW, "Low", "blue"),
54
+ (MEDIUM, "Medium", "yellow"),
55
+ (HIGH, "High", "orange"),
56
+ (CRITICAL, "Critical", "red"),
57
+ ]
58
+
59
+
60
+ class CVEStatusChoices(ChoiceSet):
61
+ key = "CVE.status"
62
+
63
+ AWAITING_REVIEW = "awaiting_review"
64
+ IN_REVIEW = "in_review"
65
+ RESOLVED = "resolved"
66
+ FALSE_POSITIVE = "false_positive"
67
+
68
+ CHOICES = [
69
+ (AWAITING_REVIEW, "Awaiting Review", "cyan"),
70
+ (IN_REVIEW, "In Review", "blue"),
71
+ (RESOLVED, "Resolved", "green"),
72
+ (FALSE_POSITIVE, "False Positive", "gray"),
73
+ ]
74
+
75
+
76
+ class VulnerabilityStatusChoices(ChoiceSet):
77
+ key = "Vulnerability.status"
78
+
79
+ OPEN = "open"
80
+ MITIGATED = "mitigated"
81
+ RESOLVED = "resolved"
82
+ ACCEPTED_RISK = "accepted_risk"
83
+ IGNORED = "ignored"
84
+
85
+ CHOICES = [
86
+ (OPEN, "Open", "red"),
87
+ (MITIGATED, "Mitigated", "yellow"),
88
+ (RESOLVED, "Resolved", "green"),
89
+ (ACCEPTED_RISK, "Accepted Risk", "purple"),
90
+ (IGNORED, "Ignored", "gray"),
91
+ ]
@@ -0,0 +1,169 @@
1
+ import django_filters
2
+ from django.db.models import Q
3
+
4
+ from dcim.models import Device, DeviceRole, DeviceType, ModuleType, Platform
5
+ from netbox.filtersets import NetBoxModelFilterSet
6
+
7
+ from .choices import (
8
+ ContractSupportLevelChoices,
9
+ CVESeverityChoices,
10
+ CVEStatusChoices,
11
+ VulnerabilityStatusChoices,
12
+ )
13
+ from .models import (
14
+ CVE,
15
+ Contract,
16
+ DeviceSoftware,
17
+ HardwareNotice,
18
+ Provider,
19
+ SoftwareImageFile,
20
+ SoftwareVersion,
21
+ ValidatedSoftware,
22
+ Vulnerability,
23
+ )
24
+
25
+
26
+ class ProviderFilterSet(NetBoxModelFilterSet):
27
+ class Meta:
28
+ model = Provider
29
+ fields = ("id", "name", "phone", "email")
30
+
31
+ def search(self, queryset, name, value):
32
+ if not value.strip():
33
+ return queryset
34
+ return queryset.filter(
35
+ Q(name__icontains=value) | Q(email__icontains=value) | Q(phone__icontains=value)
36
+ )
37
+
38
+
39
+ class ContractFilterSet(NetBoxModelFilterSet):
40
+ provider_id = django_filters.ModelMultipleChoiceFilter(queryset=Provider.objects.all())
41
+ support_level = django_filters.MultipleChoiceFilter(choices=ContractSupportLevelChoices)
42
+ device_id = django_filters.ModelMultipleChoiceFilter(
43
+ field_name="devices", queryset=Device.objects.all()
44
+ )
45
+
46
+ class Meta:
47
+ model = Contract
48
+ fields = ("id", "name", "contract_number", "provider_id", "support_level")
49
+
50
+ def search(self, queryset, name, value):
51
+ if not value.strip():
52
+ return queryset
53
+ return queryset.filter(Q(name__icontains=value) | Q(contract_number__icontains=value))
54
+
55
+
56
+ class HardwareNoticeFilterSet(NetBoxModelFilterSet):
57
+ device_type_id = django_filters.ModelMultipleChoiceFilter(queryset=DeviceType.objects.all())
58
+ module_type_id = django_filters.ModelMultipleChoiceFilter(queryset=ModuleType.objects.all())
59
+
60
+ class Meta:
61
+ model = HardwareNotice
62
+ fields = ("id", "device_type_id", "module_type_id")
63
+
64
+ def search(self, queryset, name, value):
65
+ if not value.strip():
66
+ return queryset
67
+ return queryset.filter(
68
+ Q(device_type__model__icontains=value) | Q(module_type__model__icontains=value)
69
+ )
70
+
71
+
72
+ class SoftwareVersionFilterSet(NetBoxModelFilterSet):
73
+ platform_id = django_filters.ModelMultipleChoiceFilter(queryset=Platform.objects.all())
74
+ long_term_support = django_filters.BooleanFilter()
75
+
76
+ class Meta:
77
+ model = SoftwareVersion
78
+ fields = ("id", "platform_id", "version", "long_term_support")
79
+
80
+ def search(self, queryset, name, value):
81
+ if not value.strip():
82
+ return queryset
83
+ return queryset.filter(Q(version__icontains=value) | Q(alias__icontains=value))
84
+
85
+
86
+ class SoftwareImageFileFilterSet(NetBoxModelFilterSet):
87
+ software_version_id = django_filters.ModelMultipleChoiceFilter(
88
+ queryset=SoftwareVersion.objects.all()
89
+ )
90
+
91
+ class Meta:
92
+ model = SoftwareImageFile
93
+ fields = ("id", "software_version_id", "file_name", "default_image")
94
+
95
+ def search(self, queryset, name, value):
96
+ if not value.strip():
97
+ return queryset
98
+ return queryset.filter(Q(file_name__icontains=value) | Q(checksum__icontains=value))
99
+
100
+
101
+ class DeviceSoftwareFilterSet(NetBoxModelFilterSet):
102
+ device_id = django_filters.ModelMultipleChoiceFilter(queryset=Device.objects.all())
103
+ software_version_id = django_filters.ModelMultipleChoiceFilter(
104
+ queryset=SoftwareVersion.objects.all()
105
+ )
106
+
107
+ class Meta:
108
+ model = DeviceSoftware
109
+ fields = ("id", "device_id", "software_version_id")
110
+
111
+ def search(self, queryset, name, value):
112
+ if not value.strip():
113
+ return queryset
114
+ return queryset.filter(Q(device__name__icontains=value))
115
+
116
+
117
+ class ValidatedSoftwareFilterSet(NetBoxModelFilterSet):
118
+ software_version_id = django_filters.ModelMultipleChoiceFilter(
119
+ queryset=SoftwareVersion.objects.all()
120
+ )
121
+ device_type_id = django_filters.ModelMultipleChoiceFilter(
122
+ field_name="device_types", queryset=DeviceType.objects.all()
123
+ )
124
+ device_role_id = django_filters.ModelMultipleChoiceFilter(
125
+ field_name="device_roles", queryset=DeviceRole.objects.all()
126
+ )
127
+ preferred = django_filters.BooleanFilter()
128
+
129
+ class Meta:
130
+ model = ValidatedSoftware
131
+ fields = ("id", "software_version_id", "preferred")
132
+
133
+ def search(self, queryset, name, value):
134
+ return queryset
135
+
136
+
137
+ class CVEFilterSet(NetBoxModelFilterSet):
138
+ severity = django_filters.MultipleChoiceFilter(choices=CVESeverityChoices)
139
+ status = django_filters.MultipleChoiceFilter(choices=CVEStatusChoices)
140
+ affected_software_id = django_filters.ModelMultipleChoiceFilter(
141
+ field_name="affected_software", queryset=SoftwareVersion.objects.all()
142
+ )
143
+
144
+ class Meta:
145
+ model = CVE
146
+ fields = ("id", "cve_id", "severity", "status")
147
+
148
+ def search(self, queryset, name, value):
149
+ if not value.strip():
150
+ return queryset
151
+ return queryset.filter(
152
+ Q(cve_id__icontains=value) | Q(name__icontains=value) | Q(description__icontains=value)
153
+ )
154
+
155
+
156
+ class VulnerabilityFilterSet(NetBoxModelFilterSet):
157
+ cve_id = django_filters.ModelMultipleChoiceFilter(queryset=CVE.objects.all())
158
+ device_id = django_filters.ModelMultipleChoiceFilter(queryset=Device.objects.all())
159
+ software_version_id = django_filters.ModelMultipleChoiceFilter(
160
+ queryset=SoftwareVersion.objects.all()
161
+ )
162
+ status = django_filters.MultipleChoiceFilter(choices=VulnerabilityStatusChoices)
163
+
164
+ class Meta:
165
+ model = Vulnerability
166
+ fields = ("id", "cve_id", "device_id", "software_version_id", "status")
167
+
168
+ def search(self, queryset, name, value):
169
+ return queryset