feat(edr): OCSF mappers + ingestion for 6 EDR integrations
Every EDR (category: endpoint) integration is now audited for an OCSF mapper. Six had a fetch command but no mapper — add a bundled OCSF mapper for each, wire the fetch command as an ingestion source (ingest: results_path/dedup_key [/incremental_field]) and add the top-level ingestion block. Field mappings were derived from each vendor's fetch output and cross-referenced against the demisto/content reference for that vendor. - carbon-black-cloud: search_alerts (results_path results, dedup id) — 35 fields - cisco-secure-endpoint: list_events (data, id) — 21 fields - cybereason: query_malops (malops, guid, incr start_time) — 6 fields - sophos-central: list_alerts (items, id) — 14 fields - trend-vision-one: list_alerts (items, id, incr start_datetime) — 19 fields - withsecure: list_incidents (items, incidentId) — 7 fields Validated: every manifest passes ParseManifest+ValidateManifest and every mapper passes ParseMapperFile with all JSONata source_path/field expressions compiling. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -84,7 +84,7 @@ commands:
|
|||||||
outputs_schema: { properties: {} }
|
outputs_schema: { properties: {} }
|
||||||
- id: search_alerts
|
- id: search_alerts
|
||||||
name: cbc-search-alerts
|
name: cbc-search-alerts
|
||||||
description: "Search alerts."
|
description: "Search alerts. Used for ingestion: results path = results."
|
||||||
risk: read
|
risk: read
|
||||||
inputs_schema:
|
inputs_schema:
|
||||||
properties:
|
properties:
|
||||||
@@ -92,6 +92,9 @@ commands:
|
|||||||
rows: { type: number, description: "Max alerts (default 50)" }
|
rows: { type: number, description: "Max alerts (default 50)" }
|
||||||
required: []
|
required: []
|
||||||
outputs_schema: { properties: {} }
|
outputs_schema: { properties: {} }
|
||||||
|
ingest:
|
||||||
|
results_path: results
|
||||||
|
dedup_key: id
|
||||||
- id: ban_hash
|
- id: ban_hash
|
||||||
name: cbc-ban-hash
|
name: cbc-ban-hash
|
||||||
description: "Ban a file by SHA-256 hash (reputation deny-list override)."
|
description: "Ban a file by SHA-256 hash (reputation deny-list override)."
|
||||||
@@ -119,3 +122,8 @@ commands:
|
|||||||
properties: {}
|
properties: {}
|
||||||
required: []
|
required: []
|
||||||
outputs_schema: { properties: {} }
|
outputs_schema: { properties: {} }
|
||||||
|
|
||||||
|
ingestion:
|
||||||
|
command: search_alerts
|
||||||
|
mapper: search_alerts
|
||||||
|
default_incident_type: "Carbon Black Cloud Alert"
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
name: "VMware Carbon Black Cloud Alerts → OCSF"
|
||||||
|
description: "Exhaustive map of a Carbon Black Cloud Alert Search v7 alert (POST /api/alerts/v7/orgs/{org_key}/alerts/_search, results_path = results) to OCSF. Field paths validated against the CBC Platform Alerts v7 API. The alerting process = actor (actor.*); the child/target process spawned as a result = process.*; parent lineage under actor.process.parent_process.*."
|
||||||
|
field_mappings:
|
||||||
|
title: "reason"
|
||||||
|
severity: "severity >= 9 ? 5 : (severity >= 7 ? 4 : (severity >= 5 ? 3 : (severity >= 3 ? 2 : 1)))"
|
||||||
|
description: "type"
|
||||||
|
# results_path = results; source_path is JSONata over ONE alert object.
|
||||||
|
# Paths absent from a given alert (e.g. no childproc.* on a non-process alert type) are
|
||||||
|
# skipped at ingestion, so extra entries are safe.
|
||||||
|
ocsf:
|
||||||
|
# ── Finding / alert identity ───────────────────────────────────────
|
||||||
|
- { source_path: "id", ocsf_field: "finding_info.uid" }
|
||||||
|
- { source_path: "reason", ocsf_field: "finding_info.title" }
|
||||||
|
- { source_path: "type", ocsf_field: "finding_info.desc" }
|
||||||
|
- { source_path: "first_event_timestamp", ocsf_field: "finding_info.created_time" }
|
||||||
|
- { source_path: "backend_update_timestamp", ocsf_field: "finding_info.modified_time" }
|
||||||
|
- { source_path: "alert_url", ocsf_field: "finding_info.src_url" }
|
||||||
|
- { source_path: "workflow.status", ocsf_field: "status" }
|
||||||
|
- { source_path: "determination.value", ocsf_field: "status_detail" }
|
||||||
|
# ── Endpoint / device ──────────────────────────────────────────────
|
||||||
|
- { source_path: "device_id", ocsf_field: "device.uid" }
|
||||||
|
- { source_path: "device_os_version", ocsf_field: "device.os.build" }
|
||||||
|
- { source_path: "device_name", ocsf_field: "src_endpoint.hostname" }
|
||||||
|
- { source_path: "device_os", ocsf_field: "src_endpoint.os.name" }
|
||||||
|
- { source_path: "device_internal_ip", ocsf_field: "src_endpoint.ip" }
|
||||||
|
- { source_path: "device_username", ocsf_field: "user.name" }
|
||||||
|
- { source_path: "org_key", ocsf_field: "cloud.account.uid" }
|
||||||
|
# ── Triggering process — the actor ─────────────────────────────────
|
||||||
|
- { source_path: "process_name", ocsf_field: "actor.process.name" }
|
||||||
|
- { source_path: "process_pid", ocsf_field: "actor.process.pid" }
|
||||||
|
- { source_path: "process_cmdline", ocsf_field: "actor.process.cmd_line" }
|
||||||
|
- { source_path: "process_sha256", ocsf_field: "actor.process.file.hashes.sha256" }
|
||||||
|
- { source_path: "process_md5", ocsf_field: "actor.process.file.hashes.md5" }
|
||||||
|
- { source_path: "process_guid", ocsf_field: "metadata.original_event_uid" }
|
||||||
|
- { source_path: "process_username", ocsf_field: "actor.user.name" }
|
||||||
|
# ── Parent process ──────────────────────────────────────────────────
|
||||||
|
- { source_path: "parent_name", ocsf_field: "actor.process.parent_process.name" }
|
||||||
|
- { source_path: "parent_pid", ocsf_field: "actor.process.parent_process.pid" }
|
||||||
|
- { source_path: "parent_cmdline", ocsf_field: "actor.process.parent_process.cmd_line" }
|
||||||
|
- { source_path: "parent_sha256", ocsf_field: "actor.process.parent_process.file.hashes.sha256" }
|
||||||
|
# ── Child / target process ──────────────────────────────────────────
|
||||||
|
- { source_path: "childproc_name", ocsf_field: "process.name" }
|
||||||
|
- { source_path: "childproc_pid", ocsf_field: "process.pid" }
|
||||||
|
- { source_path: "childproc_cmdline", ocsf_field: "process.cmd_line" }
|
||||||
|
- { source_path: "childproc_guid", ocsf_field: "process.uid" }
|
||||||
|
# ── Detection rule / watchlist / report ─────────────────────────────
|
||||||
|
- { source_path: "watchlists[0].name", ocsf_field: "rule.name" }
|
||||||
|
- { source_path: "watchlists[0].id", ocsf_field: "rule.uid" }
|
||||||
|
- { source_path: "report_name", ocsf_field: "rule.desc" }
|
||||||
|
# ── IOC / observable ──────────────────────────────────────────────
|
||||||
|
- { source_path: "ioc_hit", ocsf_field: "observables.value" }
|
||||||
|
- { source_path: "ioc_field", ocsf_field: "observables.type" }
|
||||||
@@ -62,7 +62,7 @@ commands:
|
|||||||
outputs_schema: { properties: {} }
|
outputs_schema: { properties: {} }
|
||||||
- id: list_events
|
- id: list_events
|
||||||
name: cisco-amp-list-events
|
name: cisco-amp-list-events
|
||||||
description: "List events."
|
description: "List events. Used for ingestion: results path = data."
|
||||||
risk: read
|
risk: read
|
||||||
inputs_schema:
|
inputs_schema:
|
||||||
properties:
|
properties:
|
||||||
@@ -70,6 +70,9 @@ commands:
|
|||||||
limit: { type: number, description: "Max events (default 50)" }
|
limit: { type: number, description: "Max events (default 50)" }
|
||||||
required: []
|
required: []
|
||||||
outputs_schema: { properties: {} }
|
outputs_schema: { properties: {} }
|
||||||
|
ingest:
|
||||||
|
results_path: data
|
||||||
|
dedup_key: id
|
||||||
- id: get_trajectory
|
- id: get_trajectory
|
||||||
name: cisco-amp-get-trajectory
|
name: cisco-amp-get-trajectory
|
||||||
description: "Get a computer's device trajectory."
|
description: "Get a computer's device trajectory."
|
||||||
@@ -88,3 +91,8 @@ commands:
|
|||||||
properties: {}
|
properties: {}
|
||||||
required: []
|
required: []
|
||||||
outputs_schema: { properties: {} }
|
outputs_schema: { properties: {} }
|
||||||
|
|
||||||
|
ingestion:
|
||||||
|
command: list_events
|
||||||
|
mapper: list_events
|
||||||
|
default_incident_type: "Cisco Secure Endpoint Event"
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
name: "Cisco Secure Endpoint Events → OCSF"
|
||||||
|
description: "Maps a Cisco AMP for Endpoints event object (GET /v1/events, results_path = data) to OCSF. The detected file is the subject (file.*/malware.*); the process that dropped/ran it (file.parent.*) is the actor (actor.process.*). Field paths validated against the AMP API v1 event schema (Cisco docs + demisto/content CiscoAMP pack README)."
|
||||||
|
field_mappings:
|
||||||
|
title: "detection ? detection : event_type"
|
||||||
|
severity: "severity = 'Critical' ? 5 : (severity = 'High' ? 4 : (severity = 'Medium' ? 3 : 2))"
|
||||||
|
description: "event_type"
|
||||||
|
# results_path = data; source_path is JSONata over ONE event object.
|
||||||
|
# Paths absent from a given event are skipped at ingestion, so extra entries are safe.
|
||||||
|
ocsf:
|
||||||
|
# ── Endpoint / device ──────────────────────────────────────────────
|
||||||
|
- { source_path: "computer.hostname", ocsf_field: "src_endpoint.hostname" }
|
||||||
|
- { source_path: "computer.external_ip", ocsf_field: "src_endpoint.ip" }
|
||||||
|
- { source_path: "computer.connector_guid", ocsf_field: "device.uid" }
|
||||||
|
- { source_path: "computer.user", ocsf_field: "user.name" }
|
||||||
|
# ── Finding / analytic ─────────────────────────────────────────────
|
||||||
|
- { source_path: "id", ocsf_field: "finding_info.uid" }
|
||||||
|
- { source_path: "timestamp", ocsf_field: "finding_info.created_time" }
|
||||||
|
- { source_path: "event_type", ocsf_field: "finding_info.analytic.name" }
|
||||||
|
- { source_path: "event_type_id", ocsf_field: "finding_info.analytic.uid" }
|
||||||
|
- { source_path: "file.disposition", ocsf_field: "disposition" }
|
||||||
|
# ── Malware / detection ────────────────────────────────────────────
|
||||||
|
- { source_path: "detection", ocsf_field: "malware.name" }
|
||||||
|
- { source_path: "detection_id", ocsf_field: "malware.uid" }
|
||||||
|
# ── Detected file — the subject ────────────────────────────────────
|
||||||
|
- { source_path: "file.file_name", ocsf_field: "file.name" }
|
||||||
|
- { source_path: "file.file_path", ocsf_field: "file.path" }
|
||||||
|
- { source_path: "file.identity.sha256", ocsf_field: "file.hashes.sha256" }
|
||||||
|
- { source_path: "file.identity.sha1", ocsf_field: "file.hashes.sha1" }
|
||||||
|
- { source_path: "file.identity.md5", ocsf_field: "file.hashes.md5" }
|
||||||
|
# ── Parent process (dropped/ran the file) — the actor ──────────────
|
||||||
|
- { source_path: "file.parent.file_name", ocsf_field: "actor.process.name" }
|
||||||
|
- { source_path: "file.parent.process_id", ocsf_field: "actor.process.pid" }
|
||||||
|
- { source_path: "file.parent.identity.sha256", ocsf_field: "actor.process.file.hashes.sha256" }
|
||||||
|
- { source_path: "file.parent.identity.sha1", ocsf_field: "actor.process.file.hashes.sha1" }
|
||||||
|
- { source_path: "file.parent.identity.md5", ocsf_field: "actor.process.file.hashes.md5" }
|
||||||
@@ -31,7 +31,7 @@ config_schema:
|
|||||||
commands:
|
commands:
|
||||||
- id: query_malops
|
- id: query_malops
|
||||||
name: cybereason-query-malops
|
name: cybereason-query-malops
|
||||||
description: "Query Malops (malicious operations) in a time window."
|
description: "Query Malops (malicious operations) in a time window. Used for ingestion: results path = malops."
|
||||||
risk: read
|
risk: read
|
||||||
inputs_schema:
|
inputs_schema:
|
||||||
properties:
|
properties:
|
||||||
@@ -39,6 +39,10 @@ commands:
|
|||||||
end_time: { type: number, description: "End time as Unix epoch milliseconds" }
|
end_time: { type: number, description: "End time as Unix epoch milliseconds" }
|
||||||
required: []
|
required: []
|
||||||
outputs_schema: { properties: {} }
|
outputs_schema: { properties: {} }
|
||||||
|
ingest:
|
||||||
|
results_path: malops
|
||||||
|
dedup_key: guid
|
||||||
|
incremental_field: start_time
|
||||||
- id: list_sensors
|
- id: list_sensors
|
||||||
name: cybereason-list-sensors
|
name: cybereason-list-sensors
|
||||||
description: "List sensors (endpoints)."
|
description: "List sensors (endpoints)."
|
||||||
@@ -93,3 +97,8 @@ commands:
|
|||||||
properties: {}
|
properties: {}
|
||||||
required: []
|
required: []
|
||||||
outputs_schema: { properties: {} }
|
outputs_schema: { properties: {} }
|
||||||
|
|
||||||
|
ingestion:
|
||||||
|
command: query_malops
|
||||||
|
mapper: query_malops
|
||||||
|
default_incident_type: "Cybereason Malop"
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
name: "Cybereason Malops → OCSF"
|
||||||
|
description: "Maps the raw items of the 'malops' array returned by POST /rest/detection/inbox (results_path = malops) to OCSF finding fields. Each element is the flat, non-nested Malop-inbox shape (guid, edr, displayName, status, severity, creationTime, machines[], users[]) — not the enriched elementValues/simpleValues shape returned by /rest/crimes/unified."
|
||||||
|
field_mappings:
|
||||||
|
title: "displayName"
|
||||||
|
severity: "severity = 'Critical' ? 5 : (severity = 'High' ? 4 : (severity = 'Medium' ? 3 : (severity = 'Low' ? 2 : 3)))"
|
||||||
|
description: "\"Cybereason Malop — severity: \" & severity & \", status: \" & status"
|
||||||
|
ocsf:
|
||||||
|
- { source_path: "guid", ocsf_field: "finding_info.uid" }
|
||||||
|
- { source_path: "displayName", ocsf_field: "finding_info.title" }
|
||||||
|
- { source_path: "creationTime", ocsf_field: "finding_info.created_time" }
|
||||||
|
- { source_path: "status", ocsf_field: "status" }
|
||||||
|
- { source_path: "machines[0].displayName", ocsf_field: "src_endpoint.hostname" }
|
||||||
|
- { source_path: "$count(machines)", ocsf_field: "count" }
|
||||||
@@ -67,13 +67,16 @@ commands:
|
|||||||
outputs_schema: { properties: {} }
|
outputs_schema: { properties: {} }
|
||||||
- id: list_alerts
|
- id: list_alerts
|
||||||
name: sophos-list-alerts
|
name: sophos-list-alerts
|
||||||
description: "List alerts."
|
description: "List alerts. Used for ingestion: results path = items."
|
||||||
risk: read
|
risk: read
|
||||||
inputs_schema:
|
inputs_schema:
|
||||||
properties:
|
properties:
|
||||||
limit: { type: number, description: "Max alerts (default 50)" }
|
limit: { type: number, description: "Max alerts (default 50)" }
|
||||||
required: []
|
required: []
|
||||||
outputs_schema: { properties: {} }
|
outputs_schema: { properties: {} }
|
||||||
|
ingest:
|
||||||
|
results_path: items
|
||||||
|
dedup_key: id
|
||||||
|
|
||||||
- id: test_connection
|
- id: test_connection
|
||||||
name: sophos-test-connection
|
name: sophos-test-connection
|
||||||
@@ -83,3 +86,8 @@ commands:
|
|||||||
properties: {}
|
properties: {}
|
||||||
required: []
|
required: []
|
||||||
outputs_schema: { properties: {} }
|
outputs_schema: { properties: {} }
|
||||||
|
|
||||||
|
ingestion:
|
||||||
|
command: list_alerts
|
||||||
|
mapper: list_alerts
|
||||||
|
default_incident_type: "Sophos Central Alert"
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
name: "Sophos Central Alerts → OCSF"
|
||||||
|
description: "Maps a Sophos Central alert (GET /common/v1/alerts, results_path = items) to OCSF Detection Finding fields. Sophos severity is a string enum (high/medium/low); managedAgent is the affected endpoint."
|
||||||
|
field_mappings:
|
||||||
|
title: "description"
|
||||||
|
description: "description"
|
||||||
|
# Sophos severity enum → 1-5 incident scale. Right-associative chaining, no parentheses;
|
||||||
|
# the last band uses a literal else so 'low' and anything unknown land on 2.
|
||||||
|
severity: "severity = 'high' ? 4 : severity = 'medium' ? 3 : 2"
|
||||||
|
# Product that raised the alert (e.g. endpoint, server, mobile).
|
||||||
|
source: "product"
|
||||||
|
# results_path = items; source_path is JSONata over ONE alert object using RAW field names.
|
||||||
|
# Fields absent from a given alert return nothing and are skipped.
|
||||||
|
ocsf:
|
||||||
|
# ── Finding ───────────────────────────────────────────────────────
|
||||||
|
- { source_path: "id", ocsf_field: "finding_info.uid" }
|
||||||
|
- { source_path: "description", ocsf_field: "finding_info.title" }
|
||||||
|
- { source_path: "groupKey", ocsf_field: "finding_info.desc" }
|
||||||
|
- { source_path: "raisedAt", ocsf_field: "finding_info.created_time" }
|
||||||
|
- { source_path: "type", ocsf_field: "finding_info.analytic.type" }
|
||||||
|
- { source_path: "severity", ocsf_field: "severity" }
|
||||||
|
# ── Alert classification ──────────────────────────────────────────
|
||||||
|
- { source_path: "category", ocsf_field: "rule.category" }
|
||||||
|
- { source_path: "type", ocsf_field: "rule.name" }
|
||||||
|
# ── Affected endpoint (managedAgent) ──────────────────────────────
|
||||||
|
- { source_path: "managedAgent.name", ocsf_field: "src_endpoint.hostname" }
|
||||||
|
- { source_path: "managedAgent.id", ocsf_field: "device.uid" }
|
||||||
|
- { source_path: "managedAgent.type", ocsf_field: "device.type" }
|
||||||
|
# ── Referenced person ─────────────────────────────────────────────
|
||||||
|
- { source_path: "person.name", ocsf_field: "user.name" }
|
||||||
|
# ── Provenance ────────────────────────────────────────────────────
|
||||||
|
- { source_path: "product", ocsf_field: "metadata.product.name" }
|
||||||
|
- { source_path: "tenant.id", ocsf_field: "metadata.tenant_uid" }
|
||||||
@@ -64,7 +64,7 @@ commands:
|
|||||||
outputs_schema: { properties: {} }
|
outputs_schema: { properties: {} }
|
||||||
- id: list_alerts
|
- id: list_alerts
|
||||||
name: tmv1-list-alerts
|
name: tmv1-list-alerts
|
||||||
description: "List Workbench alerts in a time window."
|
description: "List Workbench alerts in a time window. Used for ingestion: results path = items."
|
||||||
risk: read
|
risk: read
|
||||||
inputs_schema:
|
inputs_schema:
|
||||||
properties:
|
properties:
|
||||||
@@ -73,6 +73,10 @@ commands:
|
|||||||
top: { type: number, description: "Max alerts (default 50)" }
|
top: { type: number, description: "Max alerts (default 50)" }
|
||||||
required: []
|
required: []
|
||||||
outputs_schema: { properties: {} }
|
outputs_schema: { properties: {} }
|
||||||
|
ingest:
|
||||||
|
results_path: items
|
||||||
|
dedup_key: id
|
||||||
|
incremental_field: start_datetime
|
||||||
- id: get_alert
|
- id: get_alert
|
||||||
name: tmv1-get-alert
|
name: tmv1-get-alert
|
||||||
description: "Get a single Workbench alert by ID."
|
description: "Get a single Workbench alert by ID."
|
||||||
@@ -110,3 +114,8 @@ commands:
|
|||||||
properties: {}
|
properties: {}
|
||||||
required: []
|
required: []
|
||||||
outputs_schema: { properties: {} }
|
outputs_schema: { properties: {} }
|
||||||
|
|
||||||
|
ingestion:
|
||||||
|
command: list_alerts
|
||||||
|
mapper: list_alerts
|
||||||
|
default_incident_type: "Trend Vision One Alert"
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
name: "Trend Micro Vision One Workbench Alerts → OCSF"
|
||||||
|
description: "Maps a Vision One Workbench alert (GET /v3.0/workbench/alerts, results_path = items) to OCSF finding fields. Field names verified against the v3.0 Workbench alert schema (demisto/content TrendMicroVisionOneV3 + trendmicro/tm-v1-api-cookbook). Vision One severity is a string (critical/high/medium/low/info); impactScope entities are typed (host/account/emailAddress/…) — first host → src_endpoint, first account → user."
|
||||||
|
field_mappings:
|
||||||
|
title: "model"
|
||||||
|
severity: "severity = 'critical' ? 5 : (severity = 'high' ? 4 : (severity = 'medium' ? 3 : (severity = 'low' ? 2 : 1)))"
|
||||||
|
description: "description"
|
||||||
|
# results_path = items; source_path is JSONata over ONE alert object.
|
||||||
|
# Paths absent from a given alert are skipped at ingestion, so extra entries are safe.
|
||||||
|
ocsf:
|
||||||
|
# ── Finding / analytic ────────────────────────────────────────────
|
||||||
|
- { source_path: "id", ocsf_field: "finding_info.uid" }
|
||||||
|
- { source_path: "model", ocsf_field: "finding_info.title" }
|
||||||
|
- { source_path: "description", ocsf_field: "finding_info.desc" }
|
||||||
|
- { source_path: "createdDateTime", ocsf_field: "finding_info.created_time" }
|
||||||
|
- { source_path: "updatedDateTime", ocsf_field: "finding_info.modified_time" }
|
||||||
|
- { source_path: "workbenchLink", ocsf_field: "finding_info.src_url" }
|
||||||
|
- { source_path: "score", ocsf_field: "confidence_score" }
|
||||||
|
- { source_path: "investigationStatus", ocsf_field: "status" }
|
||||||
|
# ── Detection model as the rule ───────────────────────────────────
|
||||||
|
- { source_path: "model", ocsf_field: "rule.name" }
|
||||||
|
- { source_path: "modelId", ocsf_field: "rule.uid" }
|
||||||
|
# ── MITRE ATT&CK (nested under matchedRules[].matchedFilters[]) ────
|
||||||
|
- { source_path: "matchedRules[0].matchedFilters[0].mitreTechniqueIds[0]", ocsf_field: "attacks.technique.uid" }
|
||||||
|
# ── Impacted host — first 'host' entity → src_endpoint / device ────
|
||||||
|
- { source_path: "impactScope.entities[entityType='host'][0].entityValue.name", ocsf_field: "src_endpoint.hostname" }
|
||||||
|
- { source_path: "impactScope.entities[entityType='host'][0].entityValue.ips[0]", ocsf_field: "src_endpoint.ip" }
|
||||||
|
- { source_path: "impactScope.entities[entityType='host'][0].entityValue.guid", ocsf_field: "device.uid" }
|
||||||
|
# ── Impacted account — first 'account' entity → user ──────────────
|
||||||
|
- { source_path: "impactScope.entities[entityType='account'][0].entityValue", ocsf_field: "user.name" }
|
||||||
|
# ── IOC / observable (first indicator) ────────────────────────────
|
||||||
|
- { source_path: "indicators[0].value", ocsf_field: "observables.value" }
|
||||||
|
- { source_path: "indicators[0].type", ocsf_field: "observables.type" }
|
||||||
|
- { source_path: "indicators[0].field", ocsf_field: "observables.name" }
|
||||||
|
# ── Product provenance ────────────────────────────────────────────
|
||||||
|
- { source_path: "alertProvider", ocsf_field: "metadata.product.name" }
|
||||||
@@ -70,13 +70,16 @@ commands:
|
|||||||
outputs_schema: { properties: {} }
|
outputs_schema: { properties: {} }
|
||||||
- id: list_incidents
|
- id: list_incidents
|
||||||
name: withsecure-list-incidents
|
name: withsecure-list-incidents
|
||||||
description: "List incidents (detections)."
|
description: "List incidents (detections). Used for ingestion: results path = items."
|
||||||
risk: read
|
risk: read
|
||||||
inputs_schema:
|
inputs_schema:
|
||||||
properties:
|
properties:
|
||||||
limit: { type: number, description: "Max incidents (default 50)" }
|
limit: { type: number, description: "Max incidents (default 50)" }
|
||||||
required: []
|
required: []
|
||||||
outputs_schema: { properties: {} }
|
outputs_schema: { properties: {} }
|
||||||
|
ingest:
|
||||||
|
results_path: items
|
||||||
|
dedup_key: incidentId
|
||||||
|
|
||||||
- id: test_connection
|
- id: test_connection
|
||||||
name: withsecure-test-connection
|
name: withsecure-test-connection
|
||||||
@@ -86,3 +89,8 @@ commands:
|
|||||||
properties: {}
|
properties: {}
|
||||||
required: []
|
required: []
|
||||||
outputs_schema: { properties: {} }
|
outputs_schema: { properties: {} }
|
||||||
|
|
||||||
|
ingestion:
|
||||||
|
command: list_incidents
|
||||||
|
mapper: list_incidents
|
||||||
|
default_incident_type: "WithSecure Elements Incident"
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
name: "WithSecure Elements Incidents → OCSF"
|
||||||
|
description: "Maps a WithSecure Elements incident (Broad Context Detection / BCD) from GET /incidents/v1/incidents (results_path = items) to OCSF finding fields. Field paths validated against the WithSecure Connect Elements API OpenAPI spec (connect.withsecure.com/specs/elements). The incidents list object carries only incident-level metadata — device / user / process / file / MITRE fields live on the separate /incidents/v1/detections endpoint and are not present here."
|
||||||
|
field_mappings:
|
||||||
|
title: "name"
|
||||||
|
severity: "severity = 'critical' ? 5 : (severity = 'high' ? 4 : (severity = 'medium' ? 3 : (severity = 'low' ? 2 : 1)))"
|
||||||
|
description: "$join(categories, ', ')"
|
||||||
|
# results_path = items; source_path is JSONata over ONE incident (BCD) object.
|
||||||
|
# Paths absent from a given incident are skipped at ingestion, so extra entries are safe.
|
||||||
|
ocsf:
|
||||||
|
# ── Finding identity ──────────────────────────────────────────────
|
||||||
|
- { source_path: "incidentId", ocsf_field: "finding_info.uid" }
|
||||||
|
- { source_path: "name", ocsf_field: "finding_info.title" }
|
||||||
|
# ── Timestamps ────────────────────────────────────────────────────
|
||||||
|
- { source_path: "createdTimestamp", ocsf_field: "finding_info.created_time" }
|
||||||
|
- { source_path: "updatedTimestamp", ocsf_field: "finding_info.modified_time" }
|
||||||
|
# ── State ─────────────────────────────────────────────────────────
|
||||||
|
- { source_path: "severity", ocsf_field: "severity" }
|
||||||
|
- { source_path: "status", ocsf_field: "status" }
|
||||||
|
- { source_path: "resolution", ocsf_field: "finding_info.desc" }
|
||||||
Reference in New Issue
Block a user