Skip to content

Commit

Permalink
Merge pull request #17 from MISP/extend-test-coverage
Browse files Browse the repository at this point in the history
add: extend coverage, fix analyst data inspection
  • Loading branch information
righel authored Jan 14, 2025
2 parents 399b358 + 217a3a6 commit faa0804
Show file tree
Hide file tree
Showing 20 changed files with 1,524 additions and 24 deletions.
5 changes: 5 additions & 0 deletions src/config.schema.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
{
"$schema": "http://json-schema.org/draft-07/schema",
"type": "object",
"required": [
"allowlist",
"compartments_rules",
"instances"
],
"properties": {
"allowlist": {
"type": "object",
Expand Down
58 changes: 39 additions & 19 deletions src/mispguard.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class MISPHTTPFlow(http.HTTPFlow):
is_sighting: bool = False
is_galaxy: bool = False
is_analyst_data: bool = False
is_analyst_data_index: bool = False
is_analyst_data_minimal_index: bool = False
is_analyst_note: bool = False
is_analyst_opinion: bool = False
is_analyst_relationship: bool = False
Expand Down Expand Up @@ -97,19 +97,21 @@ def configure(self, updated):
with open("config.schema.json", "r") as file:
schema = json.load(file)
self.config = json.load(open(ctx.options.config))

# create instances_host_mapping dictionary
self.config["instances_host_mapping"] = {}
for instance_id, instance in self.config["instances"].items():
self.config["instances_host_mapping"][instance["host"]] = instance_id
self.config["instances_host_mapping"][instance["ip"]] = instance_id

validate(
instance=self.config,
schema=schema,
format_checker=Draft202012Validator.FORMAT_CHECKER,
)

# create instances_host_mapping dictionary
self.config["instances_host_mapping"] = {}
for instance_id, instance in self.config["instances"].items():
self.config["instances_host_mapping"][
instance["host"]
] = instance_id
self.config["instances_host_mapping"][instance["ip"]] = instance_id

except Exception as e:
logger.error("failed to load config file: %s" % str(e))
exit(1)
Expand Down Expand Up @@ -236,6 +238,7 @@ def enrich_flow(self, flow: http.HTTPFlow) -> MISPHTTPFlow:
if "/analyst_data/indexMinimal" in flow.request.path:
flow.is_pull = True
flow.is_analyst_data = True
flow.is_analyst_data_minimal_index = True

if "/analyst_data/index/Note/" in flow.request.path:
flow.is_pull = True
Expand All @@ -255,7 +258,7 @@ def enrich_flow(self, flow: http.HTTPFlow) -> MISPHTTPFlow:
if "/analyst_data/filterAnalystDataForPush" in flow.request.path:
flow.is_push = True
flow.is_analyst_data = True
flow.is_analyst_data_index = True
flow.is_analyst_data_minimal_index = True

if "/analyst_data/pushAnalystData" in flow.request.path:
flow.is_push = True
Expand Down Expand Up @@ -322,7 +325,11 @@ def process_request(self, flow: MISPHTTPFlow) -> None:
rules = self.get_rules(flow)
return self.process_sightings(rules, sightings, flow)

if flow.is_push and flow.is_analyst_data and not flow.is_analyst_data_index:
if (
flow.is_push
and flow.is_analyst_data
and not flow.is_analyst_data_minimal_index
):
try:
analyst_data = flow.request.json()
logger.debug(analyst_data)
Expand Down Expand Up @@ -394,7 +401,11 @@ def process_response(self, flow: MISPHTTPFlow) -> None:
rules = self.get_rules(flow)
return self.process_sightings(rules, sightings, flow)

if flow.is_pull and flow.is_analyst_data:
if (
flow.is_pull
and flow.is_analyst_data
and not flow.is_analyst_data_minimal_index
):
try:
analyst_data = flow.response.json()
except Exception as ex:
Expand Down Expand Up @@ -491,13 +502,16 @@ def check_event_level_rules(self, rules: dict, event: dict) -> None:
self.check_event_sharing_groups_rules(rules, event)

if "Note" in event["Event"]:
self.check_analyst_data_rules(rules, event["Event"]["Note"])
for note in event["Event"]["Note"]:
self.check_analyst_data_rules(rules, note)

if "Opinion" in event["Event"]:
self.check_analyst_data_rules(rules, event["Event"]["Opinion"])
for opinion in event["Event"]["Opinion"]:
self.check_analyst_data_rules(rules, opinion)

if "Relationship" in event["Event"]:
self.check_analyst_relationship_rules(rules, event["Event"]["Relationship"])
for relationship in event["Event"]["Relationship"]:
self.check_analyst_relationship_rules(rules, relationship)

def check_attribute_level_rules(self, rules: dict, attributes: dict) -> None:
logger.debug("checking attribute level rules")
Expand All @@ -521,13 +535,16 @@ def check_attribute_level_rules(self, rules: dict, attributes: dict) -> None:
self.check_attribute_level_rules(rules, attribute["ShadowAttribute"])

if "Note" in attribute:
self.check_analyst_data_rules(rules, attribute["Note"])
for note in attribute["Note"]:
self.check_analyst_data_rules(rules, note)

if "Opinion" in attribute:
self.check_analyst_data_rules(rules, attribute["Opinion"])
for opinion in attribute["Opinion"]:
self.check_analyst_data_rules(rules, opinion)

if "Relationship" in attribute:
self.check_analyst_relationship_rules(rules, attribute["Relationship"])
for relationship in attribute["Relationship"]:
self.check_analyst_relationship_rules(rules, relationship)

def check_object_level_rules(self, rules: dict, objects: dict) -> None:
for object in objects:
Expand All @@ -540,13 +557,16 @@ def check_object_level_rules(self, rules: dict, objects: dict) -> None:
self.check_attribute_level_rules(rules, object["Attribute"])

if "Note" in object:
self.check_analyst_data_rules(rules, object["Note"])
for note in object["Note"]:
self.check_analyst_data_rules(rules, note)

if "Opinion" in object:
self.check_analyst_data_rules(rules, object["Opinion"])
for opinion in object["Opinion"]:
self.check_analyst_data_rules(rules, opinion)

if "Relationship" in object:
self.check_analyst_relationship_rules(rules, object["Relationship"])
for relationship in object["Relationship"]:
self.check_analyst_relationship_rules(rules, relationship)

def check_analyst_data_rules(self, rules: dict, analyst_data: dict) -> None:
self.check_blocked_analyst_data_distribution_levels(
Expand Down
17 changes: 17 additions & 0 deletions src/test/fixtures/test_analyst_data_index_minimal_non-blocked.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"Note": [
{
"5352d149-7cb8-4b91-a403-b3428c4b9dae": "2025-01-08 10:37:00"
}
],
"Opinion": [
{
"bc6992d6-1e38-402d-a319-b73c8de11ceb": "2025-01-08 10:37:00"
}
],
"Relationship": [
{
"d8990433-bf3b-47ab-8263-eb15ff2bd0d4": "2025-01-08 10:37:00"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
{
"Event": {
"id": "1",
"orgc_id": "1",
"org_id": "1",
"date": "2022-08-31",
"threat_level_id": "1",
"info": "blocked attribute type",
"published": false,
"uuid": "385283a1-b5e0-4e10-a532-dce11c365a56",
"attribute_count": "4",
"analysis": "0",
"timestamp": "1661956788",
"distribution": "1",
"proposal_email_lock": false,
"locked": false,
"publish_timestamp": "1661956380",
"sharing_group_id": "0",
"disable_correlation": false,
"extends_uuid": "",
"protected": null,
"event_creator_email": "[email protected]",
"Org": {
"id": "1",
"name": "HOST",
"uuid": "10c8f445-888b-4a2d-bac8-4e1e8861d595",
"local": true
},
"Orgc": {
"id": "1",
"name": "HOST",
"uuid": "10c8f445-888b-4a2d-bac8-4e1e8861d595",
"local": true
},
"Attribute": [
{
"id": "1",
"type": "ip-src",
"category": "Network activity",
"to_ids": false,
"uuid": "e37a6c99-c7dc-4e41-8c79-25e35c39df0a",
"event_id": "1",
"distribution": "5",
"timestamp": "1661956302",
"comment": "",
"sharing_group_id": "0",
"deleted": false,
"disable_correlation": false,
"object_id": "0",
"object_relation": null,
"first_seen": null,
"last_seen": null,
"value": "8.8.8.8",
"Galaxy": [],
"ShadowAttribute": [],
"Relationship": [
{
"id": "1",
"uuid": "41146bcb-2869-4cf0-8abb-015e8d1350c9",
"object_uuid": "a81a9424-a62d-4a3d-b402-917d48b124bd",
"object_type": "Attribute",
"authors": "[email protected]",
"org_uuid": "10c8f445-888b-4a2d-bac8-4e1e8861d595",
"orgc_uuid": "10c8f445-888b-4a2d-bac8-4e1e8861d595",
"created": "2024-10-30 11:09:13",
"modified": "2024-10-30 11:09:13",
"distribution": "0",
"sharing_group_id": null,
"locked": false,
"relationship_type": "Acquaintance",
"related_object_uuid": "e37a6c99-c7dc-4e41-8c79-25e35c39df0a",
"related_object_type": "Attribute",
"note_type": 2,
"note_type_name": "Relationship",
"Org": {
"id": "1",
"name": "HOST",
"uuid": "10c8f445-888b-4a2d-bac8-4e1e8861d595",
"local": true
},
"Orgc": {
"id": "1",
"name": "HOST",
"uuid": "10c8f445-888b-4a2d-bac8-4e1e8861d595",
"local": true
},
"_canEdit": true,
"related_object": {
"Attribute": {
"id": "1",
"type": "ip-src",
"category": "Network activity",
"to_ids": false,
"uuid": "e37a6c99-c7dc-4e41-8c79-25e35c39df0a",
"event_id": "1",
"distribution": "5",
"timestamp": "1661956302",
"comment": "",
"sharing_group_id": "0",
"deleted": false,
"disable_correlation": false,
"object_id": "0",
"object_relation": null,
"first_seen": null,
"last_seen": null,
"value": "2.2.2.2",
"Galaxy": [],
"ShadowAttribute": []
}
}
}
]
}
],
"ShadowAttribute": [],
"RelatedEvent": [],
"Galaxy": [],
"Object": [],
"EventReport": [],
"CryptographicKey": []
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
{
"Event": {
"id": "1",
"orgc_id": "1",
"org_id": "1",
"date": "2022-08-31",
"threat_level_id": "1",
"info": "blocked attribute type",
"published": false,
"uuid": "385283a1-b5e0-4e10-a532-dce11c365a56",
"attribute_count": "4",
"analysis": "0",
"timestamp": "1661956788",
"distribution": "1",
"proposal_email_lock": false,
"locked": false,
"publish_timestamp": "1661956380",
"sharing_group_id": "0",
"disable_correlation": false,
"extends_uuid": "",
"protected": null,
"event_creator_email": "[email protected]",
"Org": {
"id": "1",
"name": "HOST",
"uuid": "10c8f445-888b-4a2d-bac8-4e1e8861d595",
"local": true
},
"Orgc": {
"id": "1",
"name": "HOST",
"uuid": "10c8f445-888b-4a2d-bac8-4e1e8861d595",
"local": true
},
"Attribute": [
{
"id": "1",
"type": "ip-src",
"category": "Network activity",
"to_ids": false,
"uuid": "e37a6c99-c7dc-4e41-8c79-25e35c39df0a",
"event_id": "1",
"distribution": "5",
"timestamp": "1661956302",
"comment": "",
"sharing_group_id": "0",
"deleted": false,
"disable_correlation": false,
"object_id": "0",
"object_relation": null,
"first_seen": null,
"last_seen": null,
"value": "8.8.8.8",
"Galaxy": [],
"ShadowAttribute": [],
"Note": [
{
"id": "1",
"uuid": "9c0e3e20-b1ea-4473-81d2-845c4399c36d",
"object_uuid": "b3eedfc4-8ffa-41a2-875b-6c3d0e4602b8",
"object_type": "Attribute",
"authors": "[email protected]",
"org_uuid": "10c8f445-888b-4a2d-bac8-4e1e8861d595",
"orgc_uuid": "10c8f445-888b-4a2d-bac8-4e1e8861d595",
"created": "2024-10-04 08:09:39",
"modified": "2024-10-04 08:09:39",
"distribution": "0",
"sharing_group_id": null,
"locked": false,
"note": "Ceci est une note",
"language": "fr-BE",
"note_type": 0,
"note_type_name": "Note",
"Org": {
"id": "1",
"name": "HOST",
"uuid": "10c8f445-888b-4a2d-bac8-4e1e8861d595",
"local": true
},
"Orgc": {
"id": "1",
"name": "HOST",
"uuid": "10c8f445-888b-4a2d-bac8-4e1e8861d595",
"local": true
},
"_canEdit": true
}
]
}
],
"ShadowAttribute": [],
"RelatedEvent": [],
"Galaxy": [],
"Object": [],
"EventReport": [],
"CryptographicKey": []
}
}
Loading

0 comments on commit faa0804

Please sign in to comment.