Skip to content

Add sealed ETL denial analysis (replacement for #699) - #709

Merged
richiemsft merged 14 commits into
mainfrom
user/saulg/learning-mode-analyze-replacement
Aug 3, 2026
Merged

Add sealed ETL denial analysis (replacement for #699)#709
richiemsft merged 14 commits into
mainfrom
user/saulg/learning-mode-analyze-replacement

Conversation

@richiemsft

@richiemsft richiemsft commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

📖 Description

Replacement for #699, which was mistakenly marked merged when the parent
branch temporarily received child-stack history during a stack-handling
mistake. This PR restores the intended denial-analysis review boundary after
merged Integration PR #696.

Adds the denial-analysis layer following #696:

  • Introduces the cross-platform learning_mode_core denial model, summary, analysis, framing, and emission primitives.
  • Adds the Windows sealed-ETL decoder using OpenTrace/ProcessTrace and TDH metadata.
  • Decodes and normalizes file, registry, UI, and capability-related Learning Mode events.
  • Caches manifest TDH schemas per trace while bypassing the cache for self-describing TraceLogging events.
  • Contains all Rust panics inside the ETW callback boundary and resumes them only after the trace handle is closed.
  • Bounds property counts, struct depth, total decode work, metadata references, and payload reads.
  • Skips malformed individual payload events while preserving fatal schema/API errors.
  • Handles fixed-width unsupported InTypes without losing payload alignment.
  • Uses deterministic synthetic drive maps for path-normalization tests.
  • Streams raw diagnostics and adds lm_analyze as a developer-only trace diagnostic.

PR #696 has merged. This PR now targets main directly.

🔗 References

🔍 Validation

  • cargo test -p learning_mode_core
  • cargo test -p learning_mode_windows --all-targets — 82 tests
  • cargo clippy -p learning_mode_core -p learning_mode_windows --all-targets -- -D warnings
  • Feature-enabled V1 Windows VM 172.17.7.153:
    • captured a fresh 2,713-byte ETL
    • production analysis exited 0 and emitted 9 unique denials
    • raw diagnostic traversal exited 0

✅ Checklist

📋 Issue Type

  • Bug fix
  • Feature
  • Task

GitHub Actions runs the PR validation build automatically. The ADO pipeline
(MXC-PR-Build) is the Azure version of the PR pipeline, kept in parity with the GitHub
Actions build; it runs on merge to main, and Microsoft reviewers with write access can trigger it
on a PR with /azp run. See docs/pull-requests.md.

@richiemsft
richiemsft requested a review from a team as a code owner July 30, 2026 05:36
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
There may be pipelines that require an authorized user to comment /azp run to run.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds cross-platform denial primitives and Windows sealed-ETL analysis for Learning Mode captures.

Changes:

  • Adds denial models, summaries, framing, and emission.
  • Implements bounded ETL decoding, extraction, normalization, and deduplication.
  • Adds the Windows-only lm_analyze diagnostic.

Reviewed changes

Copilot reviewed 15 out of 16 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/core/learning_mode_core/src/summary.rs Defines capture summaries.
src/core/learning_mode_core/src/model.rs Defines denial wire models.
src/core/learning_mode_core/src/lib.rs Exposes the core API.
src/core/learning_mode_core/src/frame.rs Defines framed records.
src/core/learning_mode_core/src/emit.rs Emits RFC 7464 streams.
src/core/learning_mode_core/src/analyze.rs Defines analyzer abstractions.
src/core/learning_mode_core/Cargo.toml Configures the new crate.
src/Cargo.toml Registers the workspace crate.
src/Cargo.lock Records dependency changes.
src/backends/learning_mode/windows/src/tdh_decode.rs Decodes TDH properties.
src/backends/learning_mode/windows/src/path_norm.rs Normalizes Windows paths.
src/backends/learning_mode/windows/src/lib.rs Exports analyzer APIs.
src/backends/learning_mode/windows/src/extractors.rs Extracts typed denials.
src/backends/learning_mode/windows/src/etl_decode.rs Processes sealed ETL files.
src/backends/learning_mode/windows/examples/lm_analyze.rs Adds the diagnostic CLI.
src/backends/learning_mode/windows/Cargo.toml Adds the core dependency.

Comment thread src/backends/learning_mode/windows/src/extractors.rs Outdated
Comment thread src/backends/learning_mode/windows/src/tdh_decode.rs Outdated
Comment thread src/backends/learning_mode/windows/examples/lm_analyze.rs Outdated
Comment thread src/backends/learning_mode/windows/Cargo.toml
@richiemsft

Copy link
Copy Markdown
Contributor Author

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

@MGudgin MGudgin left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Adversarial review findings for the sealed ETL denial-analysis layer.

Comment thread src/backends/learning_mode/windows/src/etl_decode.rs Outdated
Comment thread src/backends/learning_mode/windows/src/tdh_decode.rs
Comment thread src/backends/learning_mode/windows/src/tdh_decode.rs
Comment thread src/backends/learning_mode/windows/src/path_norm.rs Outdated
Comment thread src/backends/learning_mode/windows/src/tdh_decode.rs
Comment thread src/backends/learning_mode/windows/src/tdh_decode.rs Outdated
Comment thread src/backends/learning_mode/windows/src/tdh_decode.rs Outdated
Comment thread src/backends/learning_mode/windows/src/extractors.rs Outdated
@richiemsft
richiemsft force-pushed the user/saulg/learning-mode-analyze-replacement branch from f5c0f96 to e8cb988 Compare July 31, 2026 20:04
@richiemsft

Copy link
Copy Markdown
Contributor Author

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

An error occurred while trying to automatically change base from user/saulg/learning-mode-endtoend to main July 31, 2026 23:57
@richiemsft
richiemsft requested a review from MGudgin July 31, 2026 23:57
richiemsft and others added 13 commits July 31, 2026 17:00
Introduce the learning_mode_core crate as the cross-platform hinge of the
captureDenials pipeline (PR4/PR5 foundation):

- model: DeniedResource / ResourceType (file|ui|network|capability|other) /
  AccessType, camelCase wire contract with round-trip + key-stability tests.
- summary: DenialSummary terminator (exitCode, totalDenials,
  deniedResourcesTruncated).
- frame: self-describing type-tagged DenialFrame (denial|summary).
- emit: RFC 7464 (0x1E-framed) NDJSON stream writer over any io::Write.
- analyze: DenialAnalyzer decode trait + AnalyzeError, implemented per-OS
  by the backend ETL decoders (Windows first).

No OS-specific code; 16 unit tests + 1 doc-test, clippy/fmt clean.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Decode the learning-mode `.etl` that CaptureSession::finish seals into
cross-platform learning_mode_core::DeniedResource values, implementing the
DenialAnalyzer trait.

- path_norm: kernel-form -> drive-letter, incl. the `\??\C:\...` /
  `\??\UNC\...` DOS-devices prefix the trace actually emits.
- tdh_decode: TDH EVENT_RECORD -> (event_id, props).
- extractors: route event 14/4907 (access check) by ObjectType
  (File -> file, Key -> registry/other, empty -> capability) and derive
  accessType from AccessMask with a File/Registry right vocabulary
  (Write > Execute > Read); event 27 -> Ui; event 28 -> capability denial
  (Denied gate, payload ProcessId). Missing/unparseable mask degrades to
  Unknown rather than dropping the denial.
- etl_decode: file-mode OpenTraceW/ProcessTrace loop + dedup by
  (user-visible path, accessType).
- examples/lm_analyze: NDJSON emit + `--raw` event dump for validation.

Event vocabulary and AccessMask classification confirmed on the GE_CURRENT
x64 VM against real block-and-log (Mode="Normal") and allow-and-log
(Mode="Permissive") captures: File/registry denials decode identically in
both modes; capability denials arrive as empty-ObjectType event 14
(permissive) or event 28 (block).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Factor the pure decode composition (extract_denial routing -> path
normalisation -> dedup) out of EtlDenialAnalyzer::analyze into
resources_from_events, and cover it with tests built from the event shapes
captured on hardware for both learning modes:

- block-and-log (Mode="Normal"): file/registry event 14 + capability event 28
- allow-and-log (Mode="Permissive"): capability folded into empty-ObjectType
  event 14 (no event 28)
- empty-path capabilities from event 14 and event 28 collapse to one resource
- non-actionable object types / not-denied records / unknown event IDs dropped

A live ETW/TDH fixture read is intentionally not used: it needs the provider
manifests registered on the machine, and a raw capture embeds token SIDs that
don't belong in a public repo.

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

Copilot-Session: dfea4d42-e8a5-42ef-978a-6434e8bf89ec
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: dfea4d42-e8a5-42ef-978a-6434e8bf89ec
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: dfea4d42-e8a5-42ef-978a-6434e8bf89ec
Allocate TRACE_EVENT_INFO storage with its required alignment and decode UTF-16 payloads from byte pairs so unaligned ETW data never forms invalid Rust references.

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

Copilot-Session: dfea4d42-e8a5-42ef-978a-6434e8bf89ec
Stream raw ETL diagnostics, honor producer pointer width, normalize Windows path aliases, correct access masks and empty identifiers, and serialize FILETIME losslessly for JSON consumers.

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

Copilot-Session: dfea4d42-e8a5-42ef-978a-6434e8bf89ec
Describe the record-separator-framed output as an RFC 7464 JSON text sequence rather than NDJSON across the core API and diagnostic example.

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

Copilot-Session: dfea4d42-e8a5-42ef-978a-6434e8bf89ec
Normalize DOS devices, mapped drives, MUP redirectors, and DFS paths to absolute user-visible forms while omitting pipes, relative paths, and unknown device namespaces.

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

Copilot-Session: dfea4d42-e8a5-42ef-978a-6434e8bf89ec
Document lm_analyze as a developer-only tool and explain why the sealed, policy-oriented learning-mode decoder does not directly reuse the diagnostic console's real-time display consumer.

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

Copilot-Session: dfea4d42-e8a5-42ef-978a-6434e8bf89ec
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 3a8860a9-bb20-48ef-91a1-3da8e34b92fb
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 3a8860a9-bb20-48ef-91a1-3da8e34b92fb
@richiemsft
richiemsft force-pushed the user/saulg/learning-mode-analyze-replacement branch 2 times, most recently from 4491606 to e8cb988 Compare August 1, 2026 00:06
MGudgin
MGudgin previously approved these changes Aug 1, 2026

@MGudgin MGudgin left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

You'll need to retarget at main (which may then require new signoff, not sure...)

@richiemsft
richiemsft force-pushed the user/saulg/learning-mode-analyze-replacement branch from e8cb988 to 4491606 Compare August 1, 2026 02:05
@richiemsft
richiemsft changed the base branch from user/saulg/learning-mode-endtoend to main August 1, 2026 02:06
@richiemsft
richiemsft dismissed MGudgin’s stale review August 1, 2026 02:06

The base branch was changed.

@richiemsft

Copy link
Copy Markdown
Contributor Author

@MGudgin, yup it resetted the sign-off.

@richiemsft

Copy link
Copy Markdown
Contributor Author

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

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

Copilot-Session: 3a8860a9-bb20-48ef-91a1-3da8e34b92fb
@richiemsft

Copy link
Copy Markdown
Contributor Author

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

@richiemsft
richiemsft merged commit e8dcd48 into main Aug 3, 2026
40 checks passed
@richiemsft
richiemsft deleted the user/saulg/learning-mode-analyze-replacement branch August 3, 2026 17:23
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.

3 participants