From af93f1c58abc912640bcf8c5e3d9b6b611d050f2 Mon Sep 17 00:00:00 2001 From: lullah Date: Wed, 29 Jul 2026 16:51:51 +0100 Subject: [PATCH] add admiralty filters #417 --- stixify/web/views.py | 46 +++++++++++++++++++++++++++++ tests/conftest.py | 6 ++++ tests/src/views/bundles.py | 4 ++- tests/src/views/test_file_view.py | 35 ++++++++++++++++++++++ tests/src/views/test_report_view.py | 14 +++++++++ 5 files changed, 104 insertions(+), 1 deletion(-) diff --git a/stixify/web/views.py b/stixify/web/views.py index 78b1ed1..189dc1d 100644 --- a/stixify/web/views.py +++ b/stixify/web/views.py @@ -75,6 +75,25 @@ from drf_spectacular.views import SpectacularAPIView from rest_framework.response import Response +ADMIRALTY_MARKING_MAPPING = { + "SOURCE": { + "A": "marking-definition--cf438540-077a-56c7-b68e-82fcc2bb0208", + "B": "marking-definition--b3cd9dd0-9081-5cbe-84d0-ef5bc11b8b13", + "C": "marking-definition--3545f856-c5f5-5d2f-a1ae-102e0b6028b2", + "D": "marking-definition--223ecfcc-22ce-5ece-b91c-a05a53a91959", + "E": "marking-definition--9eff5f66-33b9-5e54-9868-72179b28ae12", + "F": "marking-definition--adebda39-90c9-5ac0-9107-c26d86a6c3d8", + }, + "INFORMATION": { + "1": "marking-definition--2462b621-0825-5879-917c-082e0394bcf4", + "2": "marking-definition--9cf59b27-57f8-5250-98f4-16c462d5652c", + "3": "marking-definition--4c76ec83-d905-5ada-b0bf-8ae2fb9e9f4d", + "4": "marking-definition--c36a018d-bc8e-57a4-a39d-9e7e31d1bc17", + "5": "marking-definition--0a48adab-e7d5-5354-8a41-abf199fe2628", + "6": "marking-definition--2244db4b-ee29-5b8c-bed4-c7ac784c647a", + }, +} + class SchemaViewCached(SpectacularAPIView): _schema = None @@ -250,6 +269,15 @@ class filterset_class(FilterSet): choices=JobState.choices, ) + admiralty_source_reliability = filters.ChoiceFilter( + choices=File._meta.get_field("admiralty_source_reliability").choices, + help_text="Filter Files by the Admiralty source reliability rating assigned to them (e.g. `A`).", + ) + admiralty_information_credibility = filters.ChoiceFilter( + choices=File._meta.get_field("admiralty_information_credibility").choices, + help_text="Filter Files by the Admiralty information credibility rating assigned to them (e.g. `1`).", + ) + ai_describes_incident = filters.BooleanFilter( help_text="If `ai_content_check_provider` set in profile used to process report, AI will answer if file describes security incident. Default will show all reports, can filter those that only describe incident by setting to true." ) @@ -669,6 +697,16 @@ def get_report(cls, report_id, request=None): description="Filter the results by TLP marking of the Report object (set at file upload time).", enum=[f[0] for f in TLP_Levels.choices], ), + OpenApiParameter( + "admiralty_source_reliability", + description="Filter the results by the Admiralty source reliability marking applied to the Report object (set at file upload time). Checks the `object_marking_refs` of the Report object for the marking definition `id` matching the rating selected.", + enum=[f[0] for f in File._meta.get_field("admiralty_source_reliability").choices], + ), + OpenApiParameter( + "admiralty_information_credibility", + description="Filter the results by the Admiralty information credibility marking applied to the Report object (set at file upload time). Checks the `object_marking_refs` of the Report object for the marking definition `id` matching the rating selected.", + enum=[f[0] for f in File._meta.get_field("admiralty_information_credibility").choices], + ), OpenApiParameter( "description", description="Filter by the content in a report `description` (which contains the markdown version of the report). Will search for descriptions that contain the value entered. Search is wildcard so `exploit` will match `exploited`, `exploits`, etc.", @@ -867,6 +905,14 @@ def get_reports(self, id=None): bind_vars["tlp_level_stix_id"] = TLP_LEVEL_STIX_ID_MAPPING.get(tlp_level) filters.append("FILTER @tlp_level_stix_id IN doc.object_marking_refs") + if rating := helper.query.get("admiralty_source_reliability"): + bind_vars["admiralty_source_reliability_stix_id"] = ADMIRALTY_MARKING_MAPPING["SOURCE"].get(rating) + filters.append("FILTER @admiralty_source_reliability_stix_id IN doc.object_marking_refs") + + if rating := helper.query.get("admiralty_information_credibility"): + bind_vars["admiralty_information_credibility_stix_id"] = ADMIRALTY_MARKING_MAPPING["INFORMATION"].get(rating) + filters.append("FILTER @admiralty_information_credibility_stix_id IN doc.object_marking_refs") + if q := helper.query.get("name"): bind_vars["name"] = q.lower() filters.append("FILTER CONTAINS(LOWER(doc.name), @name)") diff --git a/tests/conftest.py b/tests/conftest.py index 78cd56e..c3a60e8 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -115,6 +115,8 @@ def more_files(stixifier_profile, identity): ai_describes_incident=True, name="First file, special", identity=identity, + admiralty_source_reliability="A", + admiralty_information_credibility="1", ), models.File.objects.create( id="aadbe23d-192c-488d-8ce9-96aa2613453f", @@ -124,6 +126,8 @@ def more_files(stixifier_profile, identity): ai_incident_classification=["other", "apt_group", "data_leak"], name="second file, not breakable", identity=identity, + admiralty_source_reliability="B", + admiralty_information_credibility="1", ), models.File.objects.create( id="bd5c8992-e1f2-42ef-8ad2-8003bc4fcedb", @@ -136,5 +140,7 @@ def more_files(stixifier_profile, identity): ai_incident_classification=["data_leak", "vulnerability"], name="Forth file, special, breakable", identity=identity, + admiralty_source_reliability="B", + admiralty_information_credibility="3", ), ] diff --git a/tests/src/views/bundles.py b/tests/src/views/bundles.py index db44bb4..908d846 100644 --- a/tests/src/views/bundles.py +++ b/tests/src/views/bundles.py @@ -83,6 +83,7 @@ "object_marking_refs": [ "marking-definition--94868c89-83c2-464b-929b-a1a8aa3c8487", "marking-definition--f92e15d9-6afc-5ae2-bb3e-85a1fd83a3b5", + "marking-definition--cf438540-077a-56c7-b68e-82fcc2bb0208", ], }, { @@ -284,7 +285,8 @@ ], "object_marking_refs": [ "marking-definition--55d920b0-5e8b-4f79-9ee9-91f868d9b421", - "marking-definition--f92e15d9-6afc-5ae2-bb3e-85a1fd83a3b5" + "marking-definition--f92e15d9-6afc-5ae2-bb3e-85a1fd83a3b5", + "marking-definition--9cf59b27-57f8-5250-98f4-16c462d5652c" ] }, { diff --git a/tests/src/views/test_file_view.py b/tests/src/views/test_file_view.py index 3e9cef4..ffb776f 100644 --- a/tests/src/views/test_file_view.py +++ b/tests/src/views/test_file_view.py @@ -368,6 +368,41 @@ def search_files(stixifier_profile, identity): "bd5c8992-e1f2-42ef-8ad2-8003bc4fcedb", ], ), + ( + dict(admiralty_source_reliability="A"), + [ + "f3848d80-b14d-4aa6-b3a6-94bce54b217e", + ], + ), + ( + dict(admiralty_source_reliability="B"), + [ + "aadbe23d-192c-488d-8ce9-96aa2613453f", + "bd5c8992-e1f2-42ef-8ad2-8003bc4fcedb", + ], + ), + ( + dict(admiralty_information_credibility="1"), + [ + "f3848d80-b14d-4aa6-b3a6-94bce54b217e", + "aadbe23d-192c-488d-8ce9-96aa2613453f", + ], + ), + ( + dict(admiralty_information_credibility="3"), + [ + "bd5c8992-e1f2-42ef-8ad2-8003bc4fcedb", + ], + ), + ( + dict( + admiralty_source_reliability="B", + admiralty_information_credibility="3", + ), + [ + "bd5c8992-e1f2-42ef-8ad2-8003bc4fcedb", + ], + ), ], ) @pytest.mark.django_db diff --git a/tests/src/views/test_report_view.py b/tests/src/views/test_report_view.py index c1a82c6..f77b279 100644 --- a/tests/src/views/test_report_view.py +++ b/tests/src/views/test_report_view.py @@ -318,6 +318,20 @@ def test_report_objects_types(client, report_id, types, api_schema): (dict(name="oThER"), ["report--ed758a1b-34fe-4fca-8178-0c30d93a03ab"]), (dict(tlp_level="clear", name="other"), []), (dict(tlp_level="amber"), ["report--ed758a1b-34fe-4fca-8178-0c30d93a03ab"]), + ( + dict(admiralty_source_reliability="A"), + ["report--52d2146c-798a-440f-942f-6fe039fb8995"], + ), + (dict(admiralty_source_reliability="B"), []), + ( + dict(admiralty_information_credibility="2"), + ["report--ed758a1b-34fe-4fca-8178-0c30d93a03ab"], + ), + (dict(admiralty_information_credibility="1"), []), + ( + dict(admiralty_source_reliability="A", name="rig"), + ["report--52d2146c-798a-440f-942f-6fe039fb8995"], + ), (dict(labels="ploit"), ["report--ed758a1b-34fe-4fca-8178-0c30d93a03ab"]), (dict(labels="steal"), ["report--52d2146c-798a-440f-942f-6fe039fb8995"]), (