Skip to content

feat(microsoft-defender-o365): mvp1/chk7 - map api data into oaevdata models (#503) - #504

Draft
Megafredo wants to merge 5 commits into
feat/501-mvp1-chk6-fetch-source-datafrom
feat/503-mvp1-chk7-map-oaevdata
Draft

feat(microsoft-defender-o365): mvp1/chk7 - map api data into oaevdata models (#503)#504
Megafredo wants to merge 5 commits into
feat/501-mvp1-chk6-fetch-source-datafrom
feat/503-mvp1-chk7-map-oaevdata

Conversation

@Megafredo

Copy link
Copy Markdown
Member

Parent Issue: #503
Parent PR (MVP): #492

Contracts

Input Contract

A single raw alert dict from the Data Fetcher — one DefenderO365SourceData instance wraps one alert:

raw_alert: dict  # single Graph Security API alert_v2 dict from DefenderO365DataFetcher.fetch_data()

Output Contract

class DefenderO365SourceData:
    """Implements SourceDataProtocol for Microsoft Defender O365 alerts."""

    def __init__(self, raw_alert: dict) -> None: ...

    def to_oaev_data(self) -> OAEVData:
        """Map alert fields to OAEVData keyed by signature type values."""
        return OAEVData(
            start_date=...,              # from firstActivityDateTime
            end_date=...,                # from lastActivityDateTime
            parent_process_name=...,     # from alert category
            source_email=...,            # from evidence sender
            player_email=...,            # from evidence recipient
            url_hash=...,                # from evidence URL
            attachment_hash=...,         # from evidence attachment
        )

    def is_prevented(self) -> bool: ...
    def is_detected(self) -> bool: ...
    def __str__(self) -> str: ...

Consumed by: SourceHandler.serialize_as_oaevdata() via Source(source_data_model=DefenderO365SourceData).

Acceptance Criteria

@data-mapping @oaev @microsoft-defender-o365

Feature: DefenderO365SourceData.to_oaev_data maps a Graph Security alert to OAEVData with 7 signature-keyed fields
  As a collector source data implementation
  I want each alert to be expressed as OAEVData with correct signature-keyed fields
  So that the matching engine can compare it against expectations

  Background:
    Given SUPPORTED_SIGNATURES is defined with 7 types
    And OAEVData accepts extra fields matching SignatureTypes enum values (extra="allow")

  Scenario Outline: Alert with full evidence maps all 7 signature fields correctly
    Given a raw Graph Security alert with:
      - firstActivityDateTime = "<first_activity_dt>"
      - lastActivityDateTime = "<last_activity_dt>"
      - category = "<category>"
      - evidence containing sender_email = "<sender_email>"
      - evidence containing player_email = "<player_email>"
      - evidence containing url_hash = "<url_hash>"
      - evidence containing attachment_hash = "<attachment_hash>"
    When to_oaev_data is called
    Then OAEVData[SIG_TYPE_START_DATE] = datetime("<first_activity_dt>")
    And OAEVData[SIG_TYPE_END_DATE] = datetime("<last_activity_dt>")
    And OAEVData[SIG_TYPE_PARENT_PROCESS_NAME] = "<category>"
    And OAEVData[SIG_TYPE_MAIL_SOURCE_EMAIL] = "<sender_email>"
    And OAEVData[SIG_TYPE_MAIL_PLAYER_EMAIL] = "<player_email>"
    And OAEVData[SIG_TYPE_MAIL_URL_HASH] = "<url_hash>"
    And OAEVData[SIG_TYPE_MAIL_ATTACHMENT_HASH] = "<attachment_hash>"

    Examples:
      | first_activity_dt        | last_activity_dt         | category | sender_email  | player_email     | url_hash | attachment_hash |
      | 2026-07-01T08:00:00Z     | 2026-07-01T10:00:00Z     | phishing | bad@evil.com  | victim@corp.com  | a1b2c3   | d4e5f6          |

  Scenario Outline: Missing firstActivityDateTime falls back to createdDateTime
    Given a raw Graph Security alert with firstActivityDateTime = None
    And createdDateTime = "<created_dt>"
    When to_oaev_data is called
    Then OAEVData[SIG_TYPE_START_DATE] = datetime("<created_dt>")

    Examples:
      | created_dt           |
      | 2026-07-05T12:00:00Z |

  Scenario Outline: Missing lastActivityDateTime falls back to lastUpdateDateTime
    Given a raw Graph Security alert with lastActivityDateTime = None
    And lastUpdateDateTime = "<last_update_dt>"
    When to_oaev_data is called
    Then OAEVData[SIG_TYPE_END_DATE] = datetime("<last_update_dt>")

    Examples:
      | last_update_dt       |
      | 2026-07-06T16:30:00Z |

  Scenario: Alert with empty evidence produces None for evidence-derived fields
    Given a raw Graph Security alert with evidence = []
    When to_oaev_data is called
    Then OAEVData[SIG_TYPE_MAIL_SOURCE_EMAIL] is None
    And OAEVData[SIG_TYPE_MAIL_PLAYER_EMAIL] is None
    And OAEVData[SIG_TYPE_MAIL_URL_HASH] is None
    And OAEVData[SIG_TYPE_MAIL_ATTACHMENT_HASH] is None
    And OAEVData[SIG_TYPE_PARENT_PROCESS_NAME] is still populated from alert category

  Scenario Outline: to_traces_data maps alert metadata to TraceData
    Given a raw Graph Security alert with:
      - title = "<title>"
      - alertWebUrl = "<url>"
      - createdDateTime = "<created_dt>"
    When to_traces_data is called
    Then TraceData.alert_name = "<title>"
    And TraceData.alert_link = "<url>"
    And TraceData.alert_date = datetime("<created_dt>")

    Examples:
      | title              | url                          | created_dt           |
      | Phishing detected  | https://security.microsoft.com/alerts/abc | 2026-07-01T08:00:00Z |

Done Checklist

  • Create src/source/defender_o365_source_data.py with DefenderO365SourceData
  • Implement to_oaev_data() mapping all 7 signature type values from Graph API alert fields
  • Add fallback logic for SIG_TYPE_START_DATE and SIG_TYPE_END_DATE date fields
  • Write unit tests: valid OAEVData mapping, fallback paths, empty evidence
  • Create a dedicated PR linked to the Umbrella issue

Closes #503

Megafredo and others added 5 commits July 16, 2026 09:17
…branch (#471)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… branch (#493)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…anch (#497)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ch (#501)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

filigran team Item from the Filigran team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(microsoft-defender-o365): mvp1/chk7 - map api data into oaevdata models

2 participants