Skip to content

feat(stream): Microsoft 365 directory-audit event type and deserializer - #1603

Open
andriikachur wants to merge 7 commits into
mainfrom
feature/microsoft-365-audit-events
Open

feat(stream): Microsoft 365 directory-audit event type and deserializer#1603
andriikachur wants to merge 7 commits into
mainfrom
feature/microsoft-365-audit-events

Conversation

@andriikachur

@andriikachur andriikachur commented Jul 30, 2026

Copy link
Copy Markdown

Summary

Additive oss-lib support for Microsoft 365 Entra directory audit events (Graph auditLogs/directoryAudits) entering the existing logs pipeline (Cassandra unified_logs + Pinot) via the generic message-type path. First stage of the MS365 audit-logs feature; the poller/listener land in the saas repos after this releases.

  • IntegratedToolType.MICROSOFT_365("microsoft-365") — enum name becomes the Pinot toolType / Logs UI filter value
  • MessageType.MICROSOFT_365_AUDIT_EVENTCASSANDRA_EVENT_LOG + KAFKA_PINOT, COMMON_TYPE
  • UnifiedEventType M365_* additions (role management + audit failures are WARNING, rest INFO)
  • EventTypeMapper mappings for directoryAudits category values (UserManagement, GroupManagement, ApplicationManagement, RoleManagement, Policy, DirectoryManagement)
  • Microsoft365AuditEventDeserializer: toolEventId = Graph audit record id (idempotent upserts across the poller's cursor overlap window), eventTimestamp from activityDateTime, result=failureM365_AUDIT_FAILURE regardless of category, unmapped category → M365_AUDIT_OTHER, details = initiatedBy + targetResources
  • PRE_ENRICHED enrichment type + PreEnrichedDataEnrichmentService: audit events carry no agentId, and IntegratedToolDataEnrichmentService populates org fields only via the agent→machine lookup — so pre-enriched payload fields (organizationId/organizationName/userId/tenantId, stamped by the per-org poller) pass through from the deserialized message instead. DeserializedDebeziumMessage gains the three fields additively.

No behavior change for existing MessageTypes; oss-tenant deploys unaffected.

Test plan

  • EventTypeMapperTest — 6 category mappings, unmapped→UNKNOWN, tool-scoping
  • Microsoft365AuditEventDeserializerTest — field mapping, tenant/org passthrough, failure override, fallback event type, timestamp fallback, null-after
  • PreEnrichedDataEnrichmentServiceTest — passthrough + TenantIdProvider fallback
  • Full mvn test green

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added support for processing Microsoft 365 directory audit events.
    • Added categorization for user, group, application, role, policy, directory, failure, and other audit events.
    • Captured tenant, organization, user, timestamps, and audit details in processed events.
    • Added pre-enriched data handling for tenant and organization information.
  • Bug Fixes

    • Improved fallback handling for missing timestamps and unmapped or failed audit operations.
  • Tests

    • Added coverage for Microsoft 365 event parsing, categorization, fallback behavior, and enrichment.

Additive support for Entra directory audit events entering the logs
pipeline via the generic message-type path:

- IntegratedToolType.MICROSOFT_365 ("microsoft-365")
- MessageType.MICROSOFT_365_AUDIT_EVENT -> CASSANDRA_EVENT_LOG + KAFKA_PINOT
- UnifiedEventType M365_* additions (RoleManagement/failures -> WARNING)
- EventTypeMapper mappings for Graph directoryAudits category values
- Microsoft365AuditEventDeserializer: toolEventId = Graph audit id
  (idempotent upserts), eventTimestamp from activityDateTime,
  result=failure -> M365_AUDIT_FAILURE, unmapped category -> M365_AUDIT_OTHER

A2.2 enrichment decision: INTEGRATED_TOOLS_EVENTS cannot supply org fields
for agentless events (machine-lookup only populates enriched data when
agentId is present), so a new PRE_ENRICHED DataEnrichmentServiceType +
PreEnrichedDataEnrichmentService passes organizationId/organizationName/
userId through from the deserialized message (populated from the
pre-enriched payload), with TenantIdProvider fallback for tenantId.
DeserializedDebeziumMessage gains organizationId/organizationName/userId
(additive; existing MessageTypes unaffected).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 099d83be-9d9d-4436-ab63-8058953103f4

📥 Commits

Reviewing files that changed from the base of the PR and between cb6fdc1 and 2485e4d.

📒 Files selected for processing (12)
  • openframe-data-cassandra/src/main/java/com/openframe/data/cassandra/model/enums/UnifiedEventType.java
  • openframe-data-kafka/src/main/java/com/openframe/data/model/enums/DataEnrichmentServiceType.java
  • openframe-data-kafka/src/main/java/com/openframe/data/model/enums/IntegratedToolType.java
  • openframe-data-kafka/src/main/java/com/openframe/data/model/enums/MessageType.java
  • openframe-stream-service-core/src/main/java/com/openframe/stream/deserializer/Microsoft365AuditEventDeserializer.java
  • openframe-stream-service-core/src/main/java/com/openframe/stream/mapping/EventTypeMapper.java
  • openframe-stream-service-core/src/main/java/com/openframe/stream/mapping/SourceEventTypes.java
  • openframe-stream-service-core/src/main/java/com/openframe/stream/model/fleet/debezium/DeserializedDebeziumMessage.java
  • openframe-stream-service-core/src/main/java/com/openframe/stream/service/PreEnrichedDataEnrichmentService.java
  • openframe-stream-service-core/src/test/java/com/openframe/stream/deserializer/Microsoft365AuditEventDeserializerTest.java
  • openframe-stream-service-core/src/test/java/com/openframe/stream/mapping/EventTypeMapperTest.java
  • openframe-stream-service-core/src/test/java/com/openframe/stream/service/PreEnrichedDataEnrichmentServiceTest.java
🚧 Files skipped from review as they are similar to previous changes (10)
  • openframe-stream-service-core/src/main/java/com/openframe/stream/mapping/EventTypeMapper.java
  • openframe-stream-service-core/src/test/java/com/openframe/stream/mapping/EventTypeMapperTest.java
  • openframe-stream-service-core/src/main/java/com/openframe/stream/model/fleet/debezium/DeserializedDebeziumMessage.java
  • openframe-data-kafka/src/main/java/com/openframe/data/model/enums/DataEnrichmentServiceType.java
  • openframe-data-cassandra/src/main/java/com/openframe/data/cassandra/model/enums/UnifiedEventType.java
  • openframe-stream-service-core/src/main/java/com/openframe/stream/deserializer/Microsoft365AuditEventDeserializer.java
  • openframe-data-kafka/src/main/java/com/openframe/data/model/enums/MessageType.java
  • openframe-stream-service-core/src/test/java/com/openframe/stream/deserializer/Microsoft365AuditEventDeserializerTest.java
  • openframe-stream-service-core/src/main/java/com/openframe/stream/service/PreEnrichedDataEnrichmentService.java
  • openframe-data-kafka/src/main/java/com/openframe/data/model/enums/IntegratedToolType.java

📝 Walkthrough

Walkthrough

Microsoft 365 Entra directory audit events are added across event contracts, category mappings, Debezium deserialization, pre-enrichment, and automated tests.

Changes

Microsoft 365 audit ingestion

Layer / File(s) Summary
Microsoft 365 event contracts
openframe-data-cassandra/.../UnifiedEventType.java, openframe-data-kafka/.../enums/*, openframe-stream-service-core/.../SourceEventTypes.java, .../EventTypeMapper.java, .../DeserializedDebeziumMessage.java
Adds Microsoft 365 event, tool, message, enrichment, source-category, unified-event, and normalized message fields.
Audit event deserialization
openframe-stream-service-core/.../Microsoft365AuditEventDeserializer.java
Deserializes audit payloads, extracts identifiers and nested details, resolves timestamps and event types, and handles failure or unmapped categories.
Pre-enriched processing
openframe-stream-service-core/.../PreEnrichedDataEnrichmentService.java
Passes through organization and user data, resolves tenant IDs, and registers the PRE_ENRICHED service type.
Validation
openframe-stream-service-core/src/test/.../Microsoft365AuditEventDeserializerTest.java, .../EventTypeMapperTest.java, .../PreEnrichedDataEnrichmentServiceTest.java
Tests field mapping, category resolution, fallback behavior, null handling, timestamp handling, and enrichment behavior.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant DebeziumMessage
  participant Microsoft365AuditEventDeserializer
  participant EventTypeMapper
  participant PreEnrichedDataEnrichmentService
  participant EventDestinations
  DebeziumMessage->>Microsoft365AuditEventDeserializer: deliver audit payload
  Microsoft365AuditEventDeserializer->>EventTypeMapper: resolve category and result
  EventTypeMapper-->>Microsoft365AuditEventDeserializer: return unified event type
  Microsoft365AuditEventDeserializer->>PreEnrichedDataEnrichmentService: provide normalized message
  PreEnrichedDataEnrichmentService-->>Microsoft365AuditEventDeserializer: return tenant and organization enrichment
  Microsoft365AuditEventDeserializer->>EventDestinations: route Cassandra and Kafka/Pinot event
Loading

Suggested reviewers: andrii-flamingo

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the primary Microsoft 365 directory-audit event support added by the pull request.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/microsoft-365-audit-events

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@openframe-stream-service-core/src/main/java/com/openframe/stream/deserializer/Microsoft365AuditEventDeserializer.java`:
- Line 61: Update Microsoft365AuditEventDeserializer.java:61 to read the
directory audit identifier from id, optionally retaining auditId only as a
fallback; update Microsoft365AuditEventDeserializerTest.java:27-35 to use id and
assert the Graph identifier is populated.
- Around line 97-107: Update Microsoft365AuditEventDeserializer.buildDetails to
also preserve the provider-supplied additionalDetails field alongside
initiatedBy and targetResources, retaining its existing value when present and
non-null. Add or update the Microsoft 365 audit fixture and assertion to verify
additionalDetails is included in the persisted details payload.
- Around line 78-82: Update Microsoft365AuditEventDeserializer’s result
classification to treat both failure and timeout values as M365_AUDIT_FAILURE
before category-based mapping. Add a regression test covering a directory audit
event with result timeout and assert it produces M365_AUDIT_FAILURE.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 892e1031-264a-4090-8422-0b4a4ca2a981

📥 Commits

Reviewing files that changed from the base of the PR and between a4c61da and 6d1fe68.

📒 Files selected for processing (12)
  • openframe-data-cassandra/src/main/java/com/openframe/data/cassandra/model/enums/UnifiedEventType.java
  • openframe-data-kafka/src/main/java/com/openframe/data/model/enums/DataEnrichmentServiceType.java
  • openframe-data-kafka/src/main/java/com/openframe/data/model/enums/IntegratedToolType.java
  • openframe-data-kafka/src/main/java/com/openframe/data/model/enums/MessageType.java
  • openframe-stream-service-core/src/main/java/com/openframe/stream/deserializer/Microsoft365AuditEventDeserializer.java
  • openframe-stream-service-core/src/main/java/com/openframe/stream/mapping/EventTypeMapper.java
  • openframe-stream-service-core/src/main/java/com/openframe/stream/mapping/SourceEventTypes.java
  • openframe-stream-service-core/src/main/java/com/openframe/stream/model/fleet/debezium/DeserializedDebeziumMessage.java
  • openframe-stream-service-core/src/main/java/com/openframe/stream/service/PreEnrichedDataEnrichmentService.java
  • openframe-stream-service-core/src/test/java/com/openframe/stream/deserializer/Microsoft365AuditEventDeserializerTest.java
  • openframe-stream-service-core/src/test/java/com/openframe/stream/mapping/EventTypeMapperTest.java
  • openframe-stream-service-core/src/test/java/com/openframe/stream/service/PreEnrichedDataEnrichmentServiceTest.java

andriikachur and others added 6 commits July 30, 2026 14:54
…itionalDetails

Review follow-up (PR #1603):
- Graph directoryAudits result can be success|failure|timeout — timeout now
  also maps to M365_AUDIT_FAILURE instead of falling through to the
  category mapping as an INFO event
- details JSON now carries provider-supplied additionalDetails alongside
  initiatedBy and targetResources (payload contract extended in the poller
  and Graph model accordingly)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ails

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant