Skip to content

feat(intune): implement Windows device compliance analyzer (#364) - #495

Merged
adamgell merged 1 commit into
mainfrom
staff/intune-364-compliance-lane-b-r1
Aug 5, 2026
Merged

feat(intune): implement Windows device compliance analyzer (#364)#495
adamgell merged 1 commit into
mainfrom
staff/intune-364-compliance-lane-b-r1

Conversation

@adamgell

@adamgell adamgell commented Aug 5, 2026

Copy link
Copy Markdown
Owner

Summary

Implements cmtraceopen_parser::intune::device::windows::compliance — pure-Rust, wasm32-compatible four-phase analyzer for Intune Windows device compliance evaluation and reporting evidence.

Supersedes the implementation on stale PR #449 (same module + 16-scenario fixture matrix + audit fixes), restacked onto current main so CI is not blocked by the unrelated company-portal std::process purity failure that failed Check & Test on the old base.

Module structure

File Purpose
models.rs Four-phase typed model: local evaluation → aggregate → reporting → access
sources.rs Envelope decoding + event/report classification into typed signals
reducer.rs Strict phase-by-phase reduction; findings derived from the finished snapshot only
rules.rs Conservative finding derivation; access-only findings capped at Low/Info
redaction.rs Deterministic privacy projection via FNV-1a keyed tokens

Invariants preserved

  • Conditional Access denials never produce local setting verdicts
  • Stale cloud state never produces local setting verdicts
  • Missing user evaluation is NotEvaluated (coverage gap), not Noncompliant
  • Custom script failure ≠ discovery noncompliant
  • Report evaluation error ≠ Noncompliant

Local verification

  • cargo test -p cmtraceopen-parser --test intune_windows_compliance16 passed
  • cargo test -p cmtraceopen-parser --test intune_skeleton_contract26 passed
  • cargo clippy -p cmtraceopen-parser --all-targets -- -D warnings → clean
  • No std::process / I/O in the compliance leaf

Relationship to open PRs

PR Issue Decision
#449 #364 Stale base (~463 commits behind); residual CI fail unrelated; ported here
#450 #362 Autopilot Larger surface; same stale-base CI fail; left for a dedicated Autopilot restack

Test plan

  • Fixture matrix (16 scenarios) green locally
  • Shared Intune fixture contract green
  • Clippy -D warnings green on parser crate
  • Full CI Check & Test (Rust) on this PR
  • Human/adversarial review of phase separation and access-confidence caps

Fixes #364

Summary by CodeRabbit

  • New Features

    • Added comprehensive Windows compliance analysis across local evaluation, aggregate status, reporting freshness, and access decisions.
    • Added evidence-backed findings for noncompliance, stale reports, access denials, missing user context, script failures, and evaluation errors.
    • Added deterministic privacy redaction for exported compliance results.
  • Bug Fixes

    • Improved handling of contradictory evidence, unavailable artifacts, unsupported schemas, invalid timestamps, and partial coverage.
  • Tests

    • Added coverage for 16 compliance scenarios, including malformed data and privacy-redaction behavior.

Fill the reserved compliance leaf with a pure four-phase reducer
(local evaluation → aggregate → reporting → access), full fixture
matrix, and deterministic privacy redaction. Ports the audited
module from PR #449 onto current main so CI is not blocked by the
stale company-portal wasm purity failure on the old base.
@github-actions github-actions Bot added device Device management related enhancement New feature or request feature New feature intune Microsoft Intune related parser Log parser related labels Aug 5, 2026
@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Changes

Windows Intune compliance

Layer / File(s) Summary
Compliance contracts and public API
crates/cmtraceopen-parser/src/intune/device/windows/compliance/mod.rs, models.rs
Adds typed compliance phases, evidence facts, snapshots, schema versions, deterministic grouping, and public analysis APIs.
Evidence decoding and phased reduction
crates/cmtraceopen-parser/src/intune/device/windows/compliance/sources.rs, reducer.rs
Decodes versioned source envelopes and computes local evaluation, aggregate state, reporting freshness, and downstream access linkage.
Finding derivation
crates/cmtraceopen-parser/src/intune/device/windows/compliance/rules.rs
Produces evidence-backed findings for local states, reporting failures, access denials, coverage gaps, contradictions, and aggregate results.
Deterministic export redaction
crates/cmtraceopen-parser/src/intune/device/windows/compliance/redaction.rs
Masks identity-bearing values and custom output while preserving compliance structure and evidence references.
Fixture matrix and integration validation
crates/cmtraceopen-parser/tests/intune_windows_compliance.rs, crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/*
Adds sixteen scenario fixtures and tests for reduction, findings, coverage, redaction, determinism, and invalid fixture mutations.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant EvidenceSources
  participant BundleDecoder
  participant ComplianceReducer
  participant FindingRules
  participant ComplianceSnapshot
  EvidenceSources->>BundleDecoder: provide versioned evidence
  BundleDecoder->>ComplianceReducer: return normalized ComplianceInput
  ComplianceReducer->>FindingRules: provide phased snapshot state
  FindingRules->>ComplianceSnapshot: attach derived findings
Loading

Possibly related PRs

  • adamgell/cmtraceopen#388: Adds the shared evidence and normalized contracts used by this compliance module.
  • adamgell/cmtraceopen#450: Adds a structurally similar pure-Rust Windows Intune evidence parser with typed models, reduction, findings, and redaction.

Suggested labels: test

🚥 Pre-merge checks | ✅ 4
✅ 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 follows Conventional Commits and accurately describes the Intune Windows compliance analyzer implementation.
Linked Issues check ✅ Passed The changes implement the four-phase analyzer, required distinctions, privacy handling, source coverage, and all 16 linked-issue scenarios [#364].
Out of Scope Changes check ✅ Passed The changes are limited to the compliance analyzer, its tests, and synthetic fixtures required by the linked issue [#364].
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch staff/intune-364-compliance-lane-b-r1

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 Biome (2.5.6)
crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/malformed-and-unknown-schema/evidence/mdm-events/current/mdm-events.json

File contains syntax errors that prevent linting: Line 5: expected } but instead the file ends


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: 13

🤖 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 `@crates/cmtraceopen-parser/src/intune/device/windows/compliance/models.rs`:
- Around line 36-56: Document each public variant of ComplianceScope and each
public field of ComplianceSettingKey with concise /// comments describing its
meaning, while preserving the existing derives, serde attributes, and types.

In `@crates/cmtraceopen-parser/src/intune/device/windows/compliance/redaction.rs`:
- Around line 44-46: Update sid_re to use case-insensitive matching and allow
the variable numeric-component forms required for short-form, domain, and
lowercase SIDs, while preserving full SID matching. Add tests covering S-1-5-18,
S-1-5-32-544, and lowercase domain SIDs through redact_text.
- Around line 25-31: Replace the unkeyed hashing in stable_token with
HMAC-SHA-256 keyed by a deployment-provided secret, and update the public
projection API and all callers to receive and propagate that secret. Keep the
secret independent of the identifier value and never serialize or derive it from
public input; preserve the stable token format using an appropriate
deterministic digest representation.

In `@crates/cmtraceopen-parser/src/intune/device/windows/compliance/reducer.rs`:
- Around line 100-103: Update analyze_compliance to classify the event set once,
then pass the resulting signals into both reduce_local and reduce_reporting.
Remove the duplicate classify_event traversal from reduce_reporting while
preserving its filtering to ReportSubmission signals, and adjust reduce_local to
consume the shared classifications so both phases use identical results.
- Around line 560-571: Update the freshness handling around the generated_at
check so a future-stamped service result is downgraded only on that result
rather than setting phase.service_freshness to Unknown. Recompute the aggregate
phase freshness after modifying the offending result, preserving stale freshness
and findings for unaffected records; use the existing result freshness field and
fold logic.
- Around line 505-507: Update the submission handling in the compliance
reduction loop to retain the newest normalized submitted_at timestamp rather
than overwriting it based on input order. Ensure report_id and
last_submission_at use consistent newest-by-timestamp semantics, and add
coverage with newest-first Submitted events asserting the final state remains
Submitted.
- Around line 132-146: Update the policy-state handling in the
ComplianceSignal::PolicyState arm to apply the same explicit ranking rule as the
neighbouring prerequisite arm: retain a definite state over Unknown while
preserving the existing observation otherwise. Add a comment documenting this
first-wins/ranking behavior, and ensure later conflicting states are not
silently treated as equivalent.

In `@crates/cmtraceopen-parser/src/intune/device/windows/compliance/rules.rs`:
- Around line 337-341: Update ComplianceReportingPhase to expose a dedicated
submission_evidence field, populate it only from report-submission event
references in reduce_reporting, and use it instead of reporting.evidence in the
submission-failure finding. Preserve service-record evidence in the general
reporting evidence collection and add the public field before publication.

In `@crates/cmtraceopen-parser/src/intune/device/windows/compliance/sources.rs`:
- Around line 528-530: The EvaluatedAt fallback accepts invalid synthetic
timestamps, preventing valid source timestamps from being used. In
crates/cmtraceopen-parser/src/intune/device/windows/compliance/sources.rs:528-530
within classify_event and :588-590 within classify_setting_report, filter
synthetic_timestamp results to those with normalized_utc present before calling
or_else, preserving fallback to the respective context source_timestamp; add a
test with a non-RFC-3339 EvaluatedAt and valid source_timestamp that asserts
evaluated_at is orderable.
- Around line 290-302: Update parse_setting_result to handle numeric verdict
tokens consistently: remove "0" from the Compliant mappings unless the parser
explicitly supports the complete numeric vocabulary. Preserve the existing
textual mappings and return None for unsupported numeric values such as "0" and
"1".
- Around line 387-394: Update the decimal handling in parse_error_code so hex
formatting preserves the full parsed i64 value instead of casting through u32.
Keep raw and decimal unchanged, and ensure values beyond 32-bit range render
without truncation, matching the existing hex-branch behavior.

In
`@crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/malformed-and-unknown-schema/manifest.json`:
- Line 29: Update both captureState entries in the malformed-and-unknown-schema
fixture manifest to "captured", preserving the fixture’s malformed JSON and
version 99 inputs so sources() and decode_bundle exercise their intended
classification paths.

In `@crates/cmtraceopen-parser/tests/intune_windows_compliance.rs`:
- Around line 579-602: Expand redaction_preserves_states_coverage_and_evidence
to compare every non-PII ComplianceSnapshot field between projected and
loaded.snapshot, including reporting, local setting state and evidence, access
decisions and evidence, and timestamps. Preserve the existing aggregate,
coverage, and finding evidence assertions, while excluding only fields
intentionally redacted.
🪄 Autofix

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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 7836b1b3-39dd-4d44-aa3e-220999779a1b

📥 Commits

Reviewing files that changed from the base of the PR and between 8064b5a and b409ce0.

📒 Files selected for processing (80)
  • crates/cmtraceopen-parser/src/intune/device/windows/compliance/mod.rs
  • crates/cmtraceopen-parser/src/intune/device/windows/compliance/models.rs
  • crates/cmtraceopen-parser/src/intune/device/windows/compliance/redaction.rs
  • crates/cmtraceopen-parser/src/intune/device/windows/compliance/reducer.rs
  • crates/cmtraceopen-parser/src/intune/device/windows/compliance/rules.rs
  • crates/cmtraceopen-parser/src/intune/device/windows/compliance/sources.rs
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/access-denied-with-matching-state/evidence/access-facts/current/access-facts.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/access-denied-with-matching-state/evidence/device-context/current/device-context.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/access-denied-with-matching-state/evidence/mdm-events/current/mdm-events.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/access-denied-with-matching-state/evidence/service-facts/current/service-facts.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/access-denied-with-matching-state/expected.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/access-denied-with-matching-state/manifest.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/access-denied-without-compliance-evidence/evidence/access-facts/current/access-facts.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/access-denied-without-compliance-evidence/evidence/device-context/current/device-context.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/access-denied-without-compliance-evidence/expected.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/access-denied-without-compliance-evidence/manifest.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/contradictory-ids-and-timestamps/evidence/device-context/current/device-context.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/contradictory-ids-and-timestamps/evidence/mdm-events/current/mdm-events.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/contradictory-ids-and-timestamps/evidence/mdm-report/current/mdm-report.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/contradictory-ids-and-timestamps/expected.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/contradictory-ids-and-timestamps/manifest.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/custom-compliance-discovery-noncompliant/evidence/custom-compliance/current/custom-compliance.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/custom-compliance-discovery-noncompliant/evidence/device-context/current/device-context.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/custom-compliance-discovery-noncompliant/expected.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/custom-compliance-discovery-noncompliant/manifest.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/custom-compliance-script-failure/evidence/custom-compliance/current/custom-compliance.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/custom-compliance-script-failure/evidence/device-context/current/device-context.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/custom-compliance-script-failure/expected.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/custom-compliance-script-failure/manifest.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/deterministic-privacy-redaction/evidence/access-facts/current/access-facts.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/deterministic-privacy-redaction/evidence/custom-compliance/current/custom-compliance.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/deterministic-privacy-redaction/evidence/device-context/current/device-context.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/deterministic-privacy-redaction/evidence/mdm-report/current/mdm-report.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/deterministic-privacy-redaction/expected.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/deterministic-privacy-redaction/manifest.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/evaluation-error/evidence/device-context/current/device-context.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/evaluation-error/evidence/mdm-events/current/mdm-events.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/evaluation-error/expected.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/evaluation-error/manifest.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/local-compliant-service-compliant/evidence/device-context/current/device-context.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/local-compliant-service-compliant/evidence/mdm-events/current/mdm-events.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/local-compliant-service-compliant/evidence/service-facts/current/service-facts.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/local-compliant-service-compliant/expected.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/local-compliant-service-compliant/manifest.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/local-compliant-stale-service-noncompliant/evidence/device-context/current/device-context.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/local-compliant-stale-service-noncompliant/evidence/mdm-events/current/mdm-events.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/local-compliant-stale-service-noncompliant/evidence/service-facts/current/service-facts.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/local-compliant-stale-service-noncompliant/expected.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/local-compliant-stale-service-noncompliant/manifest.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/local-noncompliant-setting/evidence/device-context/current/device-context.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/local-noncompliant-setting/evidence/mdm-events/current/mdm-events.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/local-noncompliant-setting/expected.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/local-noncompliant-setting/manifest.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/local-noncompliant-with-later-service-update/evidence/device-context/current/device-context.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/local-noncompliant-with-later-service-update/evidence/mdm-events/current/mdm-events.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/local-noncompliant-with-later-service-update/evidence/service-facts/current/service-facts.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/local-noncompliant-with-later-service-update/expected.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/local-noncompliant-with-later-service-update/manifest.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/malformed-and-unknown-schema/evidence/device-context/current/device-context.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/malformed-and-unknown-schema/evidence/mdm-events/current/mdm-events.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/malformed-and-unknown-schema/evidence/mdm-report/current/mdm-report.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/malformed-and-unknown-schema/expected.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/malformed-and-unknown-schema/manifest.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/partial-event-and-report-coverage/evidence/device-context/current/device-context.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/partial-event-and-report-coverage/evidence/mdm-report/current/mdm-report.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/partial-event-and-report-coverage/expected.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/partial-event-and-report-coverage/manifest.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/report-submission-failure/evidence/device-context/current/device-context.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/report-submission-failure/evidence/mdm-events/current/mdm-events.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/report-submission-failure/expected.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/report-submission-failure/manifest.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/unsupported-not-applicable-setting/evidence/device-context/current/device-context.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/unsupported-not-applicable-setting/evidence/mdm-report/current/mdm-report.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/unsupported-not-applicable-setting/expected.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/unsupported-not-applicable-setting/manifest.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/user-targeted-policy-not-evaluated/evidence/device-context/current/device-context.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/user-targeted-policy-not-evaluated/evidence/mdm-report/current/mdm-report.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/user-targeted-policy-not-evaluated/expected.json
  • crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/user-targeted-policy-not-evaluated/manifest.json
  • crates/cmtraceopen-parser/tests/intune_windows_compliance.rs

Comment on lines +36 to +56
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
#[serde(rename_all = "camelCase")]
pub enum ComplianceScope {
Device,
User,
Unknown,
}

/// The identifiers a compliance setting can be keyed on.
///
/// All three are optional because different sources supply different subsets:
/// an MDM event usually carries an OMA-DM node URI, an exported report row
/// usually carries policy and setting GUIDs. Observations are only merged when
/// they share a derived grouping token; see [`ComplianceSettingEvaluation::grouping_token`].
#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
#[serde(rename_all = "camelCase")]
pub struct ComplianceSettingKey {
pub policy_id: Option<String>,
pub setting_id: Option<String>,
pub setting_uri: Option<String>,
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Check whether the parser crate enforces missing_docs.
set -euo pipefail

fd -t f 'lib.rs' crates/cmtraceopen-parser/src --exec rg -n 'missing_docs|deny|warn' {}
fd -t f 'Cargo.toml' crates/cmtraceopen-parser --exec rg -n -A 15 '\[lints' {}
rg -n 'missing_docs|RUSTFLAGS' --iglob '*.toml' --iglob '*.yml' --iglob '*.yaml' .

Repository: adamgell/cmtraceopen

Length of output: 158


🏁 Script executed:

set -euo pipefail

printf '%s\n' '--- parser crate files ---'
git ls-files crates/cmtraceopen-parser | sed -n '1,120p'

printf '%s\n' '--- lint configuration ---'
rg -n -C 3 'missing_docs|RUSTFLAGS|\[lints\]|rustdoc|warnings' \
  --glob 'Cargo.toml' --glob '*.rs' --glob '*.yml' --glob '*.yaml' .

printf '%s\n' '--- crate root and target module ---'
for f in $(git ls-files crates/cmtraceopen-parser/src | grep -E '(^|/)(lib|models)\.rs$|cmtraceopen-parser/src/intune/device/windows/compliance/models\.rs$'); do
  echo "### $f"
  sed -n '1,180p' "$f"
done

Repository: adamgell/cmtraceopen

Length of output: 50376


🏁 Script executed:

set -euo pipefail

printf '%s\n' '--- parser manifest ---'
cat -n crates/cmtraceopen-parser/Cargo.toml

printf '%s\n' '--- parser crate root ---'
cat -n crates/cmtraceopen-parser/src/lib.rs | sed -n '1,220p'

printf '%s\n' '--- workspace lint sections ---'
rg -n -C 8 '^\[workspace\.lints|^\[lints|missing_docs|RUSTFLAGS|rustdocflags|D warnings' \
  Cargo.toml crates/cmtraceopen-parser/Cargo.toml .github .cargo 2>/dev/null || true

printf '%s\n' '--- target public-item documentation ---'
python3 - <<'PY'
from pathlib import Path
p = Path("crates/cmtraceopen-parser/src/intune/device/windows/compliance/models.rs")
lines = p.read_text().splitlines()
for i, line in enumerate(lines, 1):
    if 30 <= i <= 70:
        print(f"{i:4}: {line}")
PY

printf '%s\n' '--- change status and focused diff summary ---'
git status --short
git diff --stat -- crates/cmtraceopen-parser/src/intune/device/windows/compliance/models.rs
git diff --unified=3 -- crates/cmtraceopen-parser/src/intune/device/windows/compliance/models.rs | sed -n '1,220p'

Repository: adamgell/cmtraceopen

Length of output: 8764


Document the public variants and fields.

missing_docs is not enabled in this crate or CI. However, the path instructions require documentation for new public items. Add /// comments to the enum variants and struct fields in this module.

🤖 Prompt for 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.

In `@crates/cmtraceopen-parser/src/intune/device/windows/compliance/models.rs`
around lines 36 - 56, Document each public variant of ComplianceScope and each
public field of ComplianceSettingKey with concise /// comments describing its
meaning, while preserving the existing derives, serde attributes, and types.

Source: Path instructions

Comment on lines +25 to +31
fn stable_token(kind: &str, value: &str) -> String {
let mut hash: u64 = 0xcbf2_9ce4_8422_2325;
for byte in value.as_bytes() {
hash ^= u64::from(*byte);
hash = hash.wrapping_mul(0x0000_0100_0000_01b3);
}
format!("[{kind}:{hash:016x}]")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -e
file="crates/cmtraceopen-parser/src/intune/device/windows/compliance/redaction.rs"
printf '%s\n' '--- redaction.rs outline ---'
ast-grep outline "$file" || true
printf '%s\n' '--- redaction.rs ---'
cat -n "$file"
printf '%s\n' '--- redaction and hashing references ---'
rg -n --glob '*.rs' 'stable_token|redacted_export_projection|redact_text|Hmac|hmac|sha2|blake3|secret|key' crates src-tauri
printf '%s\n' '--- dependency manifests ---'
git ls-files '*Cargo.toml' | xargs -r rg -n 'hmac|sha2|blake3|ring|rust-crypto|secrecy'

Repository: adamgell/cmtraceopen

Length of output: 50377


🏁 Script executed:

#!/bin/bash
set -e
file="crates/cmtraceopen-parser/src/intune/device/windows/compliance/redaction.rs"
printf '%s\n' '--- redaction implementation ---'
cat -n "$file"
printf '%s\n' '--- direct callers and exports ---'
rg -n -B3 -A5 --glob '*.rs' 'redacted_export_projection|redact_text|stable_token' crates/cmtraceopen-parser/src src-tauri/src | head -n 300
printf '%s\n' '--- manifests and crypto dependencies ---'
for f in $(git ls-files '*Cargo.toml'); do
  if rg -q 'hmac|sha2|blake3|ring|rust-crypto|secrecy' "$f"; then
    printf '%s\n' "--- $f ---"
    rg -n 'hmac|sha2|blake3|ring|rust-crypto|secrecy' "$f"
  fi
done
printf '%s\n' '--- public API declarations ---'
rg -n -B3 -A8 'pub (fn|struct|enum|type|mod)|pub use' "$file" crates/cmtraceopen-parser/src/intune/device/windows/compliance/mod.rs

Repository: adamgell/cmtraceopen

Length of output: 50376


🏁 Script executed:

#!/bin/bash
set -e
printf '%s\n' '--- compliance module exports ---'
sed -n '100,145p' crates/cmtraceopen-parser/src/intune/device/windows/compliance/mod.rs
printf '%s\n' '--- compliance projection callers ---'
rg -n -B4 -A8 --glob '*.rs' 'compliance::redacted_export_projection|redacted_export_projection\([^)]*snapshot|redacted_export_projection\(' crates/cmtraceopen-parser/src src-tauri/src | rg -C3 'compliance|snapshot|redacted_export_projection' | head -n 240
printf '%s\n' '--- crate public re-exports ---'
rg -n -B3 -A4 'pub use.*compliance|pub mod compliance|pub use redaction' crates/cmtraceopen-parser/src
printf '%s\n' '--- FNV-1a candidate probe ---'
python3 - <<'PY'
def fnv1a64(value):
    h = 0xcbf29ce484222325
    for b in value.encode():
        h ^= b
        h = (h * 0x100000001b3) & ((1 << 64) - 1)
    return f"{h:016x}"

for value in [
    "alice@example.com",
    "bob@example.com",
    "device-123456",
    "tenant-abcdef",
]:
    print(f"{value} -> {fnv1a64(value)}")
PY

Repository: adamgell/cmtraceopen

Length of output: 22544


Weak Cryptography (CWE-328): Use of Weak Hash

Reachability: External · Exploitability: Trivial

Reachability path
● Entry
  crates/cmtraceopen-parser/src/intune/device/windows/compliance/mod.rs:107
  redaction
│
▼
● Sink
  crates/cmtraceopen-parser/src/intune/device/windows/compliance/redaction.rs

Replace FNV-1a with a keyed cryptographic pseudonym.

stable_token produces unkeyed 64-bit digests for exported identifiers. Recipients can enumerate candidate values and match identities offline. Update the public projection API to receive a deployment-provided secret and use HMAC-SHA-256. Never serialize or derive the secret from public input.

🤖 Prompt for 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.

In `@crates/cmtraceopen-parser/src/intune/device/windows/compliance/redaction.rs`
around lines 25 - 31, Replace the unkeyed hashing in stable_token with
HMAC-SHA-256 keyed by a deployment-provided secret, and update the public
projection API and all callers to receive and propagate that secret. Keep the
secret independent of the identifier value and never serialize or derive it from
public input; preserve the stable token format using an appropriate
deterministic digest representation.

Comment on lines +44 to +46
fn sid_re() -> &'static Regex {
static CELL: OnceLock<Regex> = OnceLock::new();
CELL.get_or_init(|| Regex::new(r"S-1-(?:\d+-){3,}\d+").expect("SID regex must compile"))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

sed -n '1,220p' crates/cmtraceopen-parser/src/intune/device/windows/compliance/redaction.rs
printf '\n-- redaction references --\n'
rg -n "redact_text|sid_re|S-1-|redaction" crates/cmtraceopen-parser/src crates/cmtraceopen-parser/tests

Repository: adamgell/cmtraceopen

Length of output: 50376


🏁 Script executed:

python3 - <<'PY'
import re
pattern = re.compile(r"S-1-(?:\d+-){3,}\d+")
cases = [
    "S-1-5-18",
    "S-1-5-32-544",
    "S-1-5-21-111-222-333-1001",
    "s-1-5-21-111-222-333-1001",
]
for value in cases:
    print(f"{value}: {bool(pattern.search(value))}")
PY

Repository: adamgell/cmtraceopen

Length of output: 259


Sensitive Data Exposure (CWE-200): Exposure of Sensitive Information to an Unauthorized Actor

Reachability: External

Reachability path
● Entry
  crates/cmtraceopen-parser/src/intune/device/windows/compliance/mod.rs:107
  redaction
│
▼
● Sink
  crates/cmtraceopen-parser/src/intune/device/windows/compliance/redaction.rs

Mask short-form and lowercase SIDs.

sid_re misses valid SIDs such as S-1-5-18, S-1-5-32-544, and lowercase domain SIDs. These values bypass redact_text and can reach the default export. Use a case-insensitive pattern with a variable number of numeric components, and add tests for these forms.

🤖 Prompt for 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.

In `@crates/cmtraceopen-parser/src/intune/device/windows/compliance/redaction.rs`
around lines 44 - 46, Update sid_re to use case-insensitive matching and allow
the variable numeric-component forms required for short-form, domain, and
lowercase SIDs, while preserving full SID matching. Add tests covering S-1-5-18,
S-1-5-32-544, and lowercase domain SIDs through redact_text.

Comment on lines +100 to +103
for event in &input.events {
evidence.push(event.context.evidence_ref.clone());
let reference = event.context.evidence_ref.clone();
match classify_event(event) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

classify_event runs twice over every event.

reduce_local classifies the full event set on line 103, then reduce_reporting classifies the same set again on line 478 and discards everything that is not a ReportSubmission.

classify_event is not cheap. Each setting observation clones named_data and the whole IntuneObservationContext (sources.rs lines 531-532). For an EVTX-derived bundle this doubles both the classification work and the allocation volume, and the second pass throws away almost all of it.

Classify once in analyze_compliance and pass the resulting signals into both phases. That also removes the risk of the two call sites drifting apart if the classification rules change.

Also applies to: 472-481

🤖 Prompt for 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.

In `@crates/cmtraceopen-parser/src/intune/device/windows/compliance/reducer.rs`
around lines 100 - 103, Update analyze_compliance to classify the event set
once, then pass the resulting signals into both reduce_local and
reduce_reporting. Remove the duplicate classify_event traversal from
reduce_reporting while preserving its filtering to ReportSubmission signals, and
adjust reduce_local to consume the shared classifications so both phases use
identical results.

Comment on lines +132 to +146
Some(ComplianceSignal::PolicyState {
policy_id,
state,
scope,
}) => {
let entry = policies.entry(policy_id.clone()).or_insert_with(|| {
CompliancePolicyObservation {
policy_id,
state,
scope,
evidence: Vec::new(),
}
});
entry.evidence.push(reference);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Policy state resolves first-wins with no contradiction signal.

or_insert_with records state and scope from the first observation only. A later observation that reports NotReceived after Received is dropped without a trace.

The neighbouring prerequisite arm on lines 115-130 handles the same situation explicitly and documents the ranking. merge_setting surfaces disagreement through identity_contradiction rather than resolving it. CompliancePolicyObservation is public output, so this branch is the only place in the module that silently picks a side.

At minimum, apply the same explicit rule the prerequisite arm uses, and state it in a comment.

♻️ Proposed change: rank a definite state over `Unknown`
                 let entry = policies.entry(policy_id.clone()).or_insert_with(|| {
                     CompliancePolicyObservation {
                         policy_id,
                         state,
                         scope,
                         evidence: Vec::new(),
                     }
                 });
+                // A definite claim outranks `Unknown`; two disagreeing definite
+                // claims are left at the first, matching the merge policy for
+                // settings rather than preferring the newer source.
+                if entry.state == CompliancePolicyState::Unknown {
+                    entry.state = state;
+                }
+                if entry.scope == ComplianceScope::Unknown {
+                    entry.scope = scope;
+                }
                 entry.evidence.push(reference);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Some(ComplianceSignal::PolicyState {
policy_id,
state,
scope,
}) => {
let entry = policies.entry(policy_id.clone()).or_insert_with(|| {
CompliancePolicyObservation {
policy_id,
state,
scope,
evidence: Vec::new(),
}
});
entry.evidence.push(reference);
}
Some(ComplianceSignal::PolicyState {
policy_id,
state,
scope,
}) => {
let entry = policies.entry(policy_id.clone()).or_insert_with(|| {
CompliancePolicyObservation {
policy_id,
state,
scope,
evidence: Vec::new(),
}
});
// A definite claim outranks `Unknown`; two disagreeing definite
// claims are left at the first, matching the merge policy for
// settings rather than preferring the newer source.
if entry.state == CompliancePolicyState::Unknown {
entry.state = state;
}
if entry.scope == ComplianceScope::Unknown {
entry.scope = scope;
}
entry.evidence.push(reference);
}
🤖 Prompt for 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.

In `@crates/cmtraceopen-parser/src/intune/device/windows/compliance/reducer.rs`
around lines 132 - 146, Update the policy-state handling in the
ComplianceSignal::PolicyState arm to apply the same explicit ranking rule as the
neighbouring prerequisite arm: retain a definite state over Unknown while
preserving the existing observation otherwise. Add a comment documenting this
first-wins/ranking behavior, and ensure later conflicting states are not
silently treated as equivalent.

Comment on lines +290 to +302
pub(super) fn parse_setting_result(raw: &str) -> Option<ComplianceSettingState> {
match canonical(raw).as_str() {
"compliant" | "pass" | "passed" | "true" | "0" => Some(ComplianceSettingState::Compliant),
"noncompliant" | "notcompliant" | "fail" | "failed" | "false" => {
Some(ComplianceSettingState::Noncompliant)
}
"error" | "evaluationerror" => Some(ComplianceSettingState::EvaluationError),
"notapplicable" | "na" | "unsupported" => Some(ComplianceSettingState::NotApplicable),
"notevaluated" | "skipped" | "pending" => Some(ComplianceSettingState::NotEvaluated),
"prerequisiteunmet" => Some(ComplianceSettingState::PrerequisiteUnmet),
_ => None,
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

"0" asserts compliance while every other numeric token asserts nothing.

Line 292 maps the token 0 to Compliant. No arm maps 1 or any other numeric token. canonical("1") is "1", which falls through to None. A source that encodes its verdict as an HRESULT or as a 0/1 integer therefore produces an affirmative Compliant for success and no verdict at all for failure. The failure then degrades to InsufficientEvidence, or to EvaluationError only if the event level happens to be Error.

The asymmetry is the risk. 0 is the only token in this table that makes a positive claim from a numeric vocabulary the module has not otherwise declared. Either drop the 0 arm so numeric verdicts are consistently declined, or add the matching nonzero handling.

♻️ Option: decline numeric verdicts consistently
-        "compliant" | "pass" | "passed" | "true" | "0" => Some(ComplianceSettingState::Compliant),
+        "compliant" | "pass" | "passed" | "true" => Some(ComplianceSettingState::Compliant),
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
pub(super) fn parse_setting_result(raw: &str) -> Option<ComplianceSettingState> {
match canonical(raw).as_str() {
"compliant" | "pass" | "passed" | "true" | "0" => Some(ComplianceSettingState::Compliant),
"noncompliant" | "notcompliant" | "fail" | "failed" | "false" => {
Some(ComplianceSettingState::Noncompliant)
}
"error" | "evaluationerror" => Some(ComplianceSettingState::EvaluationError),
"notapplicable" | "na" | "unsupported" => Some(ComplianceSettingState::NotApplicable),
"notevaluated" | "skipped" | "pending" => Some(ComplianceSettingState::NotEvaluated),
"prerequisiteunmet" => Some(ComplianceSettingState::PrerequisiteUnmet),
_ => None,
}
}
pub(super) fn parse_setting_result(raw: &str) -> Option<ComplianceSettingState> {
match canonical(raw).as_str() {
"compliant" | "pass" | "passed" | "true" => Some(ComplianceSettingState::Compliant),
"noncompliant" | "notcompliant" | "fail" | "failed" | "false" => {
Some(ComplianceSettingState::Noncompliant)
}
"error" | "evaluationerror" => Some(ComplianceSettingState::EvaluationError),
"notapplicable" | "na" | "unsupported" => Some(ComplianceSettingState::NotApplicable),
"notevaluated" | "skipped" | "pending" => Some(ComplianceSettingState::NotEvaluated),
"prerequisiteunmet" => Some(ComplianceSettingState::PrerequisiteUnmet),
_ => None,
}
}
🤖 Prompt for 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.

In `@crates/cmtraceopen-parser/src/intune/device/windows/compliance/sources.rs`
around lines 290 - 302, Update parse_setting_result to handle numeric verdict
tokens consistently: remove "0" from the Compliant mappings unless the parser
explicitly supports the complete numeric vocabulary. Preserve the existing
textual mappings and return None for unsupported numeric values such as "0" and
"1".

Comment on lines +387 to +394
if decimal_code_re().is_match(raw) {
let decimal = raw.parse::<i64>().ok();
return Some(IntuneErrorCode {
raw: raw.to_owned(),
decimal,
hex: decimal.map(|value| format!("0x{:08X}", value as u32)),
});
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

The decimal branch truncates to 32 bits, which the hex branch explicitly forbids.

Line 392 renders value as u32. The comment on lines 371-373 states that a 64-bit token must not silently become a 32-bit one, and the hex branch honors that. The decimal branch does not. parse_error_code("4294967297") yields hex: Some("0x00000001"), so the derived hex contradicts the preserved raw. The test on line 766 covers only the hex branch.

🐛 Proposed fix: widen the rendering to match the value
     if decimal_code_re().is_match(raw) {
         let decimal = raw.parse::<i64>().ok();
         return Some(IntuneErrorCode {
             raw: raw.to_owned(),
             decimal,
-            hex: decimal.map(|value| format!("0x{:08X}", value as u32)),
+            hex: decimal.map(|value| {
+                let bits = value as u64;
+                if bits <= u64::from(u32::MAX) {
+                    format!("0x{bits:08X}")
+                } else {
+                    format!("0x{bits:016X}")
+                }
+            }),
         });
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if decimal_code_re().is_match(raw) {
let decimal = raw.parse::<i64>().ok();
return Some(IntuneErrorCode {
raw: raw.to_owned(),
decimal,
hex: decimal.map(|value| format!("0x{:08X}", value as u32)),
});
}
if decimal_code_re().is_match(raw) {
let decimal = raw.parse::<i64>().ok();
return Some(IntuneErrorCode {
raw: raw.to_owned(),
decimal,
hex: decimal.map(|value| {
let bits = value as u64;
if bits <= u64::from(u32::MAX) {
format!("0x{bits:08X}")
} else {
format!("0x{bits:016X}")
}
}),
});
}
🤖 Prompt for 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.

In `@crates/cmtraceopen-parser/src/intune/device/windows/compliance/sources.rs`
around lines 387 - 394, Update the decimal handling in parse_error_code so hex
formatting preserves the full parsed i64 value instead of casting through u32.
Keep raw and decimal unchanged, and ensure values beyond 32-bit range render
without truncation, matching the existing hex-branch behavior.

Comment on lines +528 to +530
evaluated_at: named_any(data, &EVALUATED_AT_NAMES)
.map(synthetic_timestamp)
.or_else(|| event.context.source_timestamp.clone()),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

An unparseable EvaluatedAt value discards a usable source_timestamp in both classifiers. synthetic_timestamp returns Some with kind: Invalid and normalized_utc: None when parsing fails on line 621, so the .or_else fallback never runs. normalized_timestamp in reducer.rs line 721 then rejects the timestamp, latest_evaluation skips the setting, and service freshness degrades to Unknown across the snapshot.

  • crates/cmtraceopen-parser/src/intune/device/windows/compliance/sources.rs#L528-L530: in classify_event, insert .filter(|stamp| stamp.normalized_utc.is_some()) between .map(synthetic_timestamp) and .or_else(...) so a failed parse falls back to event.context.source_timestamp.
  • crates/cmtraceopen-parser/src/intune/device/windows/compliance/sources.rs#L588-L590: apply the identical .filter(...) in classify_setting_report so a failed parse falls back to report.context.source_timestamp.

Add one test that supplies a non-RFC-3339 EvaluatedAt alongside a valid source_timestamp and asserts the resulting evaluated_at is orderable.

📍 Affects 1 file
  • crates/cmtraceopen-parser/src/intune/device/windows/compliance/sources.rs#L528-L530 (this comment)
  • crates/cmtraceopen-parser/src/intune/device/windows/compliance/sources.rs#L588-L590
🤖 Prompt for 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.

In `@crates/cmtraceopen-parser/src/intune/device/windows/compliance/sources.rs`
around lines 528 - 530, The EvaluatedAt fallback accepts invalid synthetic
timestamps, preventing valid source timestamps from being used. In
crates/cmtraceopen-parser/src/intune/device/windows/compliance/sources.rs:528-530
within classify_event and :588-590 within classify_setting_report, filter
synthetic_timestamp results to those with normalized_utc present before calling
or_else, preserving fallback to the respective context source_timestamp; add a
test with a non-RFC-3339 EvaluatedAt and valid source_timestamp that asserts
evaluated_at is orderable.

"artifactId": "mdm-events",
"family": "mdmEvents",
"sourceKind": "json",
"captureState": "parseFailed",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n -C 6 'fn sources|captureState|ComplianceSourceInput|IntuneArtifactStatus' \
  crates/cmtraceopen-parser/tests/intune_windows_compliance.rs \
  crates/cmtraceopen-parser/src/intune/device/windows/compliance/sources.rs

Repository: adamgell/cmtraceopen

Length of output: 25527


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- fixture manifests and expected states ---'
for f in \
  crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/malformed-and-unknown-schema/manifest.json \
  crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/*/manifest.json
do
  [ -f "$f" ] || continue
  if grep -qE '"captureState": "(parseFailed|unsupported)"' "$f"; then
    echo "FILE: $f"
    cat -n "$f" | sed -n '20,52p'
  fi
done

printf '%s\n' '--- decode_bundle status handling ---'
cat -n crates/cmtraceopen-parser/src/intune/device/windows/compliance/sources.rs | sed -n '113,153p'

printf '%s\n' '--- fixture test expectations and scenario loader ---'
cat -n crates/cmtraceopen-parser/tests/intune_windows_compliance.rs | sed -n '80,145p'
rg -n -C 8 'malformed-and-unknown-schema|parseFailed|unsupported|captureState' \
  crates/cmtraceopen-parser/tests/intune_windows_compliance.rs \
  crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/malformed-and-unknown-schema

Repository: adamgell/cmtraceopen

Length of output: 26940


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
import json
from pathlib import Path

manifest_path = Path(
    "crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/"
    "malformed-and-unknown-schema/manifest.json"
)
manifest = json.loads(manifest_path.read_text())

mapping = {
    "captured": "Available",
    "parseFailed": "ParseFailed",
    "unsupported": "Unsupported",
}

for artifact in manifest["artifacts"]:
    if artifact["artifactId"] in {"mdm-events", "mdm-report"}:
        state = artifact["captureState"]
        assert state in mapping
        print(f'{artifact["artifactId"]}: {state} -> {mapping[state]}')

source = Path(
    "crates/cmtraceopen-parser/src/intune/device/windows/compliance/sources.rs"
).read_text()
assert "None => (source.status.clone(), None)" in source
assert "Some(problem) => (problem.status, Some(problem.detail))" in source
print("decode_bundle preserves source.status when no DecodeProblem exists")
PY

Repository: adamgell/cmtraceopen

Length of output: 303


Set both captureState values to captured. sources() maps them directly to ComplianceSourceInput.status, and decode_bundle preserves that status when decoding returns no problem. The current values can let the fixture pass without testing classification of malformed JSON and version 99.

🤖 Prompt for 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.

In
`@crates/cmtraceopen-parser/tests/fixtures/intune/device/windows/compliance/malformed-and-unknown-schema/manifest.json`
at line 29, Update both captureState entries in the malformed-and-unknown-schema
fixture manifest to "captured", preserving the fixture’s malformed JSON and
version 99 inputs so sources() and decode_bundle exercise their intended
classification paths.

Comment on lines +579 to +602
fn redaction_preserves_states_coverage_and_evidence() {
for scenario in SCENARIOS {
let loaded = load(scenario);
let projected = redacted_export_projection(&loaded.snapshot);
assert_eq!(
projected.aggregate, loaded.snapshot.aggregate,
"{scenario}: redaction must not touch the aggregate"
);
assert_eq!(
projected.coverage, loaded.snapshot.coverage,
"{scenario}: redaction must not drop coverage"
);
let ids = |snapshot: &ComplianceSnapshot| {
snapshot
.findings
.iter()
.map(|finding| (finding.finding_id.clone(), finding.evidence.clone()))
.collect::<Vec<_>>()
};
assert_eq!(
ids(&projected),
ids(&loaded.snapshot),
"{scenario}: redaction must not change which evidence a finding cites"
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Verify all non-redacted snapshot fields.

This test does not compare reporting, local setting state and evidence, access decisions and evidence, or timestamps. A redaction regression can modify those fields and still pass.

Compare every non-PII field before and after projection. Preserve the existing checks for fields that must change.

🤖 Prompt for 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.

In `@crates/cmtraceopen-parser/tests/intune_windows_compliance.rs` around lines
579 - 602, Expand redaction_preserves_states_coverage_and_evidence to compare
every non-PII ComplianceSnapshot field between projected and loaded.snapshot,
including reporting, local setting state and evidence, access decisions and
evidence, and timestamps. Preserve the existing aggregate, coverage, and finding
evidence assertions, while excluding only fields intentionally redacted.

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

Labels

device Device management related enhancement New feature or request feature New feature intune Microsoft Intune related parser Log parser related

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Intune Windows device: model compliance evaluation and reporting evidence

1 participant