Add sealed ETL denial analysis (replacement for #699) - #709
Merged
Conversation
|
Azure Pipelines: There may be pipelines that require an authorized user to comment /azp run to run. |
This was referenced Jul 30, 2026
Contributor
There was a problem hiding this comment.
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_analyzediagnostic.
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. |
Contributor
Author
|
/azp run |
|
Azure Pipelines: Successfully started running 1 pipeline(s). |
MGudgin
reviewed
Jul 31, 2026
MGudgin
left a comment
Member
There was a problem hiding this comment.
Adversarial review findings for the sealed ETL denial-analysis layer.
richiemsft
force-pushed
the
user/saulg/learning-mode-analyze-replacement
branch
from
July 31, 2026 20:04
f5c0f96 to
e8cb988
Compare
Contributor
Author
|
/azp run |
|
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
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
force-pushed
the
user/saulg/learning-mode-analyze-replacement
branch
2 times, most recently
from
August 1, 2026 00:06
4491606 to
e8cb988
Compare
MGudgin
approved these changes
Aug 1, 2026
MGudgin
previously approved these changes
Aug 1, 2026
MGudgin
left a comment
Member
There was a problem hiding this comment.
You'll need to retarget at main (which may then require new signoff, not sure...)
richiemsft
force-pushed
the
user/saulg/learning-mode-analyze-replacement
branch
from
August 1, 2026 02:05
e8cb988 to
4491606
Compare
richiemsft
changed the base branch from
user/saulg/learning-mode-endtoend
to
main
August 1, 2026 02:06
Contributor
Author
|
@MGudgin, yup it resetted the sign-off. |
Contributor
Author
|
/azp run |
|
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
Contributor
Author
|
/azp run |
|
Azure Pipelines: Successfully started running 1 pipeline(s). |
MGudgin
approved these changes
Aug 3, 2026
8 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
📖 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:
learning_mode_coredenial model, summary, analysis, framing, and emission primitives.lm_analyzeas a developer-only trace diagnostic.PR #696 has merged. This PR now targets
maindirectly.🔗 References
🔍 Validation
cargo test -p learning_mode_corecargo test -p learning_mode_windows --all-targets— 82 testscargo clippy -p learning_mode_core -p learning_mode_windows --all-targets -- -D warnings172.17.7.153:✅ Checklist
Cargo.lock, thedependency-feed-checkcheck passes (see docs/pull-requests.md)📋 Issue Type
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 GitHubActions build; it runs on merge to
main, and Microsoft reviewers with write access can trigger iton a PR with
/azp run. See docs/pull-requests.md.