Skip to content

feat(sccm): assess pure client intake coverage - #394

Merged
adamgell merged 55 commits into
codex/parser-family-skeletonfrom
codex/sccm-319-pure-intake
Aug 2, 2026
Merged

feat(sccm): assess pure client intake coverage#394
adamgell merged 55 commits into
codex/parser-family-skeletonfrom
codex/sccm-319-pure-intake

Conversation

@adamgell

@adamgell adamgell commented Jul 31, 2026

Copy link
Copy Markdown
Owner

Implements the reviewed pure-Rust #319 client intake and fixture-oracle slice on the current SCCM integration foundation.

Exact head: 269e713865cf51d578ef7edc7f0fa901163d0d90
Reviewed integration base: 34c3abaa17baeb5c1f61e0254213bd017fdd7038

Owned scope:

  • parser-only sccm::client::intake API and exports
  • bounded 11-group client source catalog projection
  • exact SCCM coverage states and deterministic current/.lo_/numbered/timestamped ordering
  • collision-safe, privacy-bounded artifact provenance
  • one physical LocationServices.log capture projected to both location and content consumers
  • unknown/lookalike sources retained as unsupported evidence
  • fail-closed wire deserialization and canonical UTC timestamp projection
  • complete typed fixture oracle for pure assessment, pending native capture facts, and pending downstream requests

Fixture matrix:

  • complete: 11 groups / 11 fragments / 11 physical / 0 gaps
  • rotations: 11 groups / 3 fragments / 3 physical / 10 gaps
  • missing-root: 11 marker fragments / 0 physical / 12 gaps
  • access-denied: 2 fragments / 1 physical / 10 gaps
  • capped: 1 physical / 11 gaps, exact 128-byte SHA assertion
  • collision: 2 physical / 10 gaps

Selected TDD checkpoints:

  • RED 44f97225 / GREEN 1081ce67: initial pure intake contract
  • RED 4791a398 / GREEN fd405bdf: provenance validation
  • RED 175461d2 / GREEN 7cf05a09: mixed-group coverage coherence
  • RED 348d4251 / GREEN 613416bc: marker/physical identity intersection
  • RED 73d2a1f0 / GREEN 73eba644: fail-closed wire projections and canonical timestamps
  • RED 8d68ed99 / GREEN f2f8bccc: exact typed fixture oracle
  • 5a870eaf: docs enumerate all seven SCCM coverage states
  • RED e6373f31 / GREEN 0284b8f8: separate parse normalization failure from fragment-boundary completeness
  • 5be9b954: close review tracking and fixture-format nits
  • 05d4bf0d: clarify manifest/oracle and coverage-order wording
  • RED public-null regression / GREEN 269e7138: stabilize explicit coverage-gap wire shape and review boundaries

Verification at this exact head:

  • cargo test --locked -p cmtraceopen-parser --test sccm_client_intake --test sccm_client_intake_fixture_contract — 48 + 3 passed
  • SCCM spine — 161 passed
  • full cmtraceopen-parser suite — passed
  • strict Clippy — passed
  • Rust 1.88 wasm32 check — passed
  • TypeScript check — passed
  • all intake JSON via jq — passed
  • scoped Rustfmt and git diff --check — passed
  • independent full-feature review through 5a870eaf — PASS
  • independent response-delta review at 5be9b954 — PASS
  • latest exact-head review adjudication and full local verification recorded in PR comments; fresh hosted review cycle pending
  • local CodeRabbit full-delta review — valid docs wording fixed; stale sha2 finding rejected because sha2 = "0.11" already compiles in dev-dependencies
  • local CodeRabbit exact final docs delta — 0 findings
  • local CodeRabbit review of 5a870eaf..5be9b954 — 0 findings

Out of scope and still open under #319:

  • additive native SCCM manifest reader/writer and Windows discovery/capture adapter
  • cardinality enforcement at the native/JSON boundary
  • temp-dir, ACL/access-denied, reparse, rotation, collision, and legacy native tests
  • real Windows acceptance
  • workflow diagnosis and cross-side correlation

This PR remains draft while fresh hosted CI, CodeRabbit, Copilot, and unresolved-thread checks run against the exact head. Issue #319 must remain open after the pure slice merges.

Issue: #319
Epic: #317

Summary by CodeRabbit

  • New Features

    • Added structured SCCM client intake assessments with artifact classification, source grouping, coverage tracking, unsupported-artifact reporting, and coverage-gap detection.
    • Added validation for metadata, identities, paths, duplicates, collisions, provenance, and completeness.
    • Assessment results now include normalized timestamps, deterministic ordering, and validated serialization.
    • Expanded recognized SCCM client artifacts and improved multi-part filename handling.
  • Documentation

    • Clarified supported intake capabilities and remaining native capture limitations.

@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR adds public SCCM client intake contracts, source definitions, validation, artifact classification, coverage assessment, deterministic ordering, catalog integration, and fixture-based contract tests.

Changes

SCCM Client Intake Feature

Layer / File(s) Summary
Intake contracts and source registry
crates/cmtraceopen-parser/src/sccm/client/..., crates/cmtraceopen-parser/src/sccm/...
Defines public intake models, serialization, validation errors, workflows, requiredness, and 11 client source groups.
Client catalog and artifact matching
crates/cmtraceopen-parser/src/sccm/catalog.rs, crates/cmtraceopen-parser/src/sccm/findings.rs, crates/cmtraceopen-parser/tests/sccm_spine_contract.rs
Adds client source memberships and catalog entries, corrects CCM-record eligibility, and supports punctuated multi-token basenames.
Assessment, validation, and coverage flow
crates/cmtraceopen-parser/src/sccm/client/intake.rs
Validates bundles, classifies rotations and unsupported artifacts, builds fragments, aggregates coverage, emits gaps, and orders results deterministically.
Contract fixtures and validation coverage
crates/cmtraceopen-parser/tests/sccm_client_intake.rs, crates/cmtraceopen-parser/tests/fixtures/sccm/client/..., docs/sccm/preparation/issue-319-client-intake.md
Updates structured fixture expectations and verifies provenance, coverage states, collisions, path safety, identity validation, and canonical serialization.

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

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant assess_client_intake
  participant BundleValidation
  participant ClientCatalog
  participant CoverageAggregation

  Caller->>assess_client_intake: SccmClientIntakeBundle
  assess_client_intake->>BundleValidation: validate bundle constraints
  BundleValidation-->>assess_client_intake: validation result
  assess_client_intake->>ClientCatalog: classify basenames and rotations
  ClientCatalog-->>assess_client_intake: normalized fragments and unsupported artifacts
  assess_client_intake->>CoverageAggregation: aggregate memberships and coverage
  CoverageAggregation-->>assess_client_intake: assessment and coverage gaps
  assess_client_intake-->>Caller: SccmClientIntakeAssessment
Loading

Possibly related issues

  • adamgell/cmtraceopen issue 319: Covers the SCCM client intake, coverage, classification, provenance, and fixture scope.
  • adamgell/cmtraceopen issue 317: Covers related client intake and source-catalog work.

Possibly related PRs

Suggested labels: test

Suggested reviewers: copilot

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 54.33% 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
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.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the primary change: assessing pure SCCM client intake coverage.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch

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

@adamgell

Copy link
Copy Markdown
Owner Author

Pure intake GREEN checkpoint — exact fd405bd

The production pure-parser slice is pushed at fd405bd.

Scope and fixture matrix:

  • 11 deterministic logical client groups;
  • complete, rotations, missing-root, access-denied, capped, and real cross-root collision scenarios;
  • exact unknown/lookalike retention;
  • one physical LocationServices.log capture shared by location/content consumers;
  • explicit absent/accessDenied/capped and fragment completeness states;
  • unsupported physical evidence retains safe fingerprint/relative-path/version/time/encoding provenance while raw host and original path remain absent.

TDD evidence:

  • 4791a39: 6 passing / 3 intended provenance regressions failing;
  • fd405bd: 9/9 focused green.

Verification: focused 9/9, spine 136/136, full parser pass, default strict Clippy pass, Rust 1.88 wasm32 pass, TypeScript pass, 12 JSON files pass, scoped Rust 1.88 formatting and diff/status checks pass. Repository-wide fmt still reports only the inherited 17 non-#319 files; the worktree is clean.

Dependency/review state: #318 is merged and consumed. Native manifest/discovery and real Windows validation remain unimplemented, so #319 stays open and no live acceptance is claimed. This draft must receive substantive exact-head CodeRabbit plus a different independent exact-head review before any merge decision.

@adamgell

Copy link
Copy Markdown
Owner Author

@coderabbitai review

Please perform a substantive review of exact head fd405bd. Focus on pure-Rust/wasm isolation, deterministic rotation/collision behavior, coverage-state conservatism, safe provenance, unknown/lookalike handling, and public-contract compatibility. A skipped or rate-limited response will not be counted as approval.

@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

expected='fd405bdf4cf527f20d3d778dedc0dc462d2f4229'
actual="$(git rev-parse HEAD)"
printf 'HEAD=%s\nEXPECTED=%s\n' "$actual" "$expected"
git status --short
git diff --name-status "${expected}^" "$expected"
printf '\n--- Changed Rust files ---\n'
git diff --name-only "${expected}^" "$expected" -- '*.rs'
printf '\n--- Intake-related outlines ---\n'
fd -e rs . | rg 'sccm|intake' | while IFS= read -r file; do
  echo "### $file"
  ast-grep outline "$file" --items all --type function,struct,enum,trait,impl 2>/dev/null || true
done
printf '\n--- Public intake/export references ---\n'
rg -n -C 3 --glob '*.rs' 'pub (mod|use)|\b(intake|Intake|Coverage|Provenance|LocationServices)\b' . || true
printf '\n--- Exact commit diff ---\n'
git diff --find-renames --find-copies --minimal "${expected}^" "$expected" -- '*.rs' '*.json' '*.toml'

Length of output: 100785


🏁 Script executed:

#!/bin/bash
set -euo pipefail

commit='fd405bdf4cf527f20d3d778dedc0dc462d2f4229'
intake='crates/cmtraceopen-parser/src/sccm/client/intake.rs'
tests='crates/cmtraceopen-parser/tests/sccm_client_intake.rs'

printf '%s\n' '--- Uncommitted intake diff ---'
git diff -- "$intake"

printf '%s\n' '--- Committed intake implementation: declarations and catalog ---'
git show "$commit:$intake" | nl -ba | sed -n '1,370p'
printf '%s\n' '--- Committed intake implementation: validation, projection, ordering ---'
git show "$commit:$intake" | nl -ba | sed -n '371,760p'

printf '%s\n' '--- Client intake tests ---'
nl -ba "$tests" | sed -n '1,460p'

printf '%s\n' '--- SCCM contract types used by intake ---'
rg -n -C 4 --glob '*.rs' \
  'enum SccmRotation|struct SccmClientIntakeArtifact|struct SccmClientIntakeBundle|enum SccmCoverageState|struct SccmArtifact|enum SccmRole' \
  crates/cmtraceopen-parser/src/sccm

printf '%s\n' '--- All committed intake call sites and construction sites ---'
rg -n -C 3 --glob '*.rs' \
  '\b(assess_client_intake|SccmClientIntakeBundle|SccmClientIntakeArtifact|SccmClientUnsupportedArtifact)\b' \
  crates/cmtraceopen-parser

Length of output: 1594


🏁 Script executed:

#!/bin/bash
set -euo pipefail

commit='fd405bdf4cf527f20d3d778dedc0dc462d2f4229'
intake='crates/cmtraceopen-parser/src/sccm/client/intake.rs'
tests='crates/cmtraceopen-parser/tests/sccm_client_intake.rs'

printf '%s\n' '--- Staged intake diff, excluded from exact-head review ---'
git diff --cached -- "$intake"

printf '%s\n' '--- Committed intake implementation: declarations and catalog ---'
git show "$commit:$intake" | sed -n '1,370p'
printf '%s\n' '--- Committed intake implementation: validation, projection, ordering ---'
git show "$commit:$intake" | sed -n '371,760p'

printf '%s\n' '--- Client intake tests ---'
sed -n '1,460p' "$tests"

printf '%s\n' '--- SCCM contract definitions used by intake ---'
rg -n -C 5 --glob '*.rs' \
  'enum SccmRotation|struct SccmClientIntakeArtifact|struct SccmClientIntakeBundle|enum SccmCoverageState|struct SccmArtifact|enum SccmRole' \
  crates/cmtraceopen-parser/src/sccm

printf '%s\n' '--- Intake API call sites and construction sites ---'
rg -n -C 3 --glob '*.rs' \
  '\b(assess_client_intake|SccmClientIntakeBundle|SccmClientIntakeArtifact|SccmClientUnsupportedArtifact)\b' \
  crates/cmtraceopen-parser

Length of output: 64753


🏁 Script executed:

#!/bin/bash
set -euo pipefail

commit='fd405bdf4cf527f20d3d778dedc0dc462d2f4229'

printf '%s\n' '--- Committed rotation and artifact model ---'
git show "$commit:crates/cmtraceopen-parser/src/sccm/models.rs" | sed -n '255,335p'
git show "$commit:crates/cmtraceopen-parser/src/sccm/models.rs" | sed -n '400,440p'

printf '%s\n' '--- All committed rotation validation and naming logic ---'
git grep -n -E 'SccmRotation|Timestamped|is_safe_.*rotation|rotation.*valid|valid.*rotation' "$commit" -- \
  'crates/cmtraceopen-parser/src' 'crates/cmtraceopen-parser/tests' || true

printf '%s\n' '--- Exact committed focused-test section with line numbers ---'
git show "$commit:crates/cmtraceopen-parser/tests/sccm_client_intake.rs" \
  | grep -n -A 42 -B 4 'malformed_rotation_and_public_provenance_values_fail_closed'

printf '%s\n' '--- Timestamped fixture manifest values ---'
fd 'manifest.json' crates/cmtraceopen-parser/tests/fixtures/sccm/client/intake \
  -x sh -c 'echo "--- $1"; grep -n -A4 -B3 "\"timestamped\"" "$1" || true' sh {}

printf '%s\n' '--- Intake public-contract documentation and schema references ---'
rg -n -C 3 --glob '!target/**' \
  'SccmClientIntake|client intake|fragmentComplete|pathFingerprint|capturedUtc|timestamped' \
  README.md docs crates/cmtraceopen-parser 2>/dev/null || true

Length of output: 201842


@adamgell I completed a substantive review of exact head fd405bdf4cf527f20d3d778dedc0dc462d2f4229.

I found one blocking issue.

  • validate_bundle validates SccmRotation::Unknown but does not validate SccmRotation::Timestamped. expected_rotated_name then accepts any timestamp text by appending it to the basename. Therefore, an artifact with SccmRotation::Timestamped("2026-bad") and basename AppEnforce.log.2026-bad passes validation and is classified as a supported client artifact. This contradicts the committed test malformed_rotation_and_public_provenance_values_fail_closed, which expects that input to fail. Validate timestamped rotation values against the required SCCM timestamp format before matching and serializing them. This preserves deterministic timestamp ordering and fail-closed public provenance.

I also confirmed these parts of the requested scope by code inspection:

  • The implementation stays in cmtraceopen-parser. It has no filesystem, Tauri, or native API dependency.
  • LocationServices.log is represented once in physical_artifacts and projects into both supported consumer groups.
  • Fragment ordering uses rotation rank, numeric or timestamp value, fingerprint, basename, and artifact ID. This is deterministic for valid rotation data.
  • Path fingerprint and relative-path collisions fail closed, including for nonphysical evidence.
  • Unsupported and lookalike artifacts remain unsupported. The public projection excludes raw host and original path.
  • Group coverage selects the most conservative supplied coverage state. Missing groups remain Absent.

I did not run tests because the review sandbox does not permit builds or test execution. The identified timestamped-rotation case indicates that the stated focused 9/9 result should be rechecked after the fix.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@adamgell

Copy link
Copy Markdown
Owner Author

@coderabbitai The reported timestamped-rotation blocker does not reproduce at exact head fd405bd.

Focused verification just rerun:

cargo test --locked -p cmtraceopen-parser --test sccm_client_intake malformed_rotation_and_public_provenance_values_fail_closed -- --exact

Result: 1 passed, 0 failed.

The finding missed the fail-closed serializer gate. crates/cmtraceopen-parser/src/sccm/client/intake.rs:373 calls serde_json::to_value on every rotation before matching. crates/cmtraceopen-parser/src/sccm/models.rs:292-295 makes Serialize reject any noncanonical timestamp, including 2026-bad. Therefore assess_client_intake returns InvalidRotation and expected_rotated_name is never reached. The permanent regression is at tests/sccm_client_intake.rs:291-298.

No code change was made because the exact head already enforces the requested invariant. Please re-check and acknowledge this finding as not applicable to fd405bd.

@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

commit='fd405bdf4cf527f20d3d778dedc0dc462d2f4229'
intake='crates/cmtraceopen-parser/src/sccm/client/intake.rs'
models='crates/cmtraceopen-parser/src/sccm/models.rs'
test_file='crates/cmtraceopen-parser/tests/sccm_client_intake.rs'

printf '%s\n' '--- exact HEAD check ---'
git rev-parse "$commit"

printf '%s\n' '--- intake validation and rotated-name paths ---'
git show "$commit:$intake" | nl -ba | \
  grep -E -C 12 'fn validate_bundle|serde_json::to_value|expected_rotated_name|InvalidRotation|Timestamped'

printf '%s\n' '--- SccmRotation serialization ---'
git show "$commit:$models" | nl -ba | \
  grep -E -C 16 'SccmRotation|Serialize|Timestamped|timestamp'

printf '%s\n' '--- permanent regression test ---'
git show "$commit:$test_file" | nl -ba | \
  grep -E -C 18 'malformed_rotation_and_public_provenance_values_fail_closed|2026-bad|InvalidRotation'

Length of output: 1353


🏁 Script executed:

#!/bin/bash
set -euo pipefail

commit='fd405bdf4cf527f20d3d778dedc0dc462d2f4229'
intake='crates/cmtraceopen-parser/src/sccm/client/intake.rs'
models='crates/cmtraceopen-parser/src/sccm/models.rs'
test_file='crates/cmtraceopen-parser/tests/sccm_client_intake.rs'

printf '%s\n' '--- intake validation and rotated-name paths ---'
git show "$commit:$intake" | \
  grep -n -E -C 12 'fn validate_bundle|serde_json::to_value|expected_rotated_name|InvalidRotation|Timestamped' || true

printf '%s\n' '--- SccmRotation serialization ---'
git show "$commit:$models" | \
  grep -n -E -C 16 'SccmRotation|Serialize|Timestamped|timestamp' || true

printf '%s\n' '--- permanent regression test ---'
git show "$commit:$test_file" | \
  grep -n -E -C 18 'malformed_rotation_and_public_provenance_values_fail_closed|2026-bad|InvalidRotation' || true

Length of output: 22412


@adamgell You are correct. I withdraw the timestamped-rotation finding.

In validate_bundle, Line 373 serializes source.artifact.rotation before classification calls expected_rotated_name. SccmRotation::serialize rejects a noncanonical Timestamped value. Therefore, SccmRotation::Timestamped("2026-bad") returns SccmClientIntakeError::InvalidRotation and cannot be classified as a supported artifact.

The regression test at crates/cmtraceopen-parser/tests/sccm_client_intake.rs, Lines 291-298, covers this path. No code change is required for this finding.

🐇


✏️ Learnings added
Learnt from: adamgell
URL: https://github.com/adamgell/cmtraceopen/pull/394

Timestamp: 2026-07-31T13:31:08.172Z
Learning: In `crates/cmtraceopen-parser`, `assess_client_intake` fails closed for malformed `SccmRotation::Timestamped` values. `validate_bundle` serializes each rotation with `serde_json::to_value` before source-group matching, and `Serialize for SccmRotation` rejects timestamps that do not use canonical `YYYYMMDD-HHMMSS` format. Therefore, malformed timestamped rotations cannot reach `expected_rotated_name`.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

You are interacting with an AI system.

@adamgell

Copy link
Copy Markdown
Owner Author

Independent exact-head review active

I own read-only review of PR #394 at exact fd405bdf4cf527f20d3d778dedc0dc462d2f4229 against a8a367c661cd17bd1e73b87724c143ec8565ffc7.

  • Fresh detached worktree: .worktrees/review-319-fd405-independent
  • No implementation worktree reuse, code edits, commits, or pushes
  • Review scope: all four changed files plus adversarial probes for rotation/order, collision and uniqueness across supported/unsupported/nonphysical inputs, LocationServices single-capture/multi-consumer projection, conservative coverage, public provenance/privacy bounds, deterministic reordering, exact catalog admission, pure Rust/wasm compatibility, and absence of diagnosis/native I/O
  • CodeRabbit exact-head context will be checked but not substituted for this independent review

A formal exact-head COMMENTED PASS or BLOCK with executable evidence will follow. PR remains draft/open.

@adamgell adamgell left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Independent exact-head review — BLOCK

Reviewed head fd405bd against base a8a367c in a fresh detached, read-only worktree. All four changed files were reviewed. CodeRabbit has substantively reviewed this exact head and formally withdrew its timestamp claim; I independently confirmed malformed numbered and timestamped rotations fail closed.

Blocking finding

[P1] Reject identity-bearing and control-bearing public provenance.

crates/cmtraceopen-parser/src/sccm/client/intake.rs:612-626 does not bound both public provenance fields to a privacy-safe grammar. is_safe_relative_path allows @, whitespace, control characters, Unicode, and arbitrary extra segments. is_safe_path_identity rejects whitespace but does not reject control characters or non-ASCII values. assess_client_intake then copies these strings into the public assessment unchanged.

An external consumer probe against this exact head passed a captured PolicyAgent artifact with relativePath evidence/client-policy-agent/RealUser@example.com/PolicyAgent.log; assessment succeeded and the identity-bearing path appeared verbatim in serialized public JSON. A second probe with pathFingerprint containing an embedded NUL also succeeded and serialized as \u0000. This violates the program privacy contract, the spine rule that raw user identity must never reach public SCCM JSON, and this PR description claim of fail-closed public provenance.

Please add focused RED regressions through assess_client_intake and public serialization for identity-bearing relative paths and control-bearing fingerprints, then validate the approved bundle layout and every emitted provenance segment/fingerprint with a bounded privacy-safe grammar. Preserve collision-safe opaque lineage, but do not accept arbitrary identity-bearing path segments.

Verified green behavior

  • Focused client intake: 9/9 passed.
  • SCCM spine: 136/136 passed.
  • Full cmtraceopen-parser suite: 738 tests passed.
  • Strict Clippy: passed.
  • Rust 1.88 wasm32-unknown-unknown check: passed.
  • Changed-file Rust 1.88 rustfmt, git diff --check, 12 intake JSON parses, detached status: passed/clean.
  • Global cargo fmt --check --all still reports the inherited 17-file non-#319 baseline; none of the four changed files differs.
  • Exact 11-group catalog, current → .lo_ → numbered → timestamped order, malformed rotation rejection, case-insensitive collision rejection across supported/unsupported inputs, deterministic input reorder, most-limiting coverage, and one physical LocationServices projection into two consumers all passed adversarial probes.
  • Production additions contain no native I/O, Tauri, Windows, network, registry/WMI, database, workflow diagnosis, ParserKind::Sccm, or duplicate CCM parser path.

This is a COMMENTED exact-head BLOCK review. PR #394 should remain draft/open. Native capture and real Windows acceptance remain explicitly pending under #319.

@adamgell

Copy link
Copy Markdown
Owner Author

Implementation ownership claim — #319 privacy correction

I own the exact-head P1 correction from fd405bd in isolated worktree /Users/Adam.Gell/repo/cmtraceopen/.worktrees/sccm-319-privacy-fd405-r2 on local branch codex/sccm-319-privacy-fd405-r2. No prior review or implementation worktree will be edited.

Owned files: crates/cmtraceopen-parser/tests/sccm_client_intake.rs and crates/cmtraceopen-parser/src/sccm/client/intake.rs only. TDD order: commit focused test-only RED for identity/control-bearing provenance, then the smallest bounded validation helpers, focused GREEN, aggregate gates, non-force push after guarding remote fd405bd. CodeRabbit will be requested again on the corrected exact head. PR remains draft/open; native collection and real Windows acceptance stay pending.

adamgell added 2 commits July 31, 2026 10:01
RED: cargo test --locked -p cmtraceopen-parser --test sccm_client_intake -- --nocapture ran 13 tests: 11 passed and 2 intended privacy regressions failed.
@adamgell

adamgell commented Jul 31, 2026

Copy link
Copy Markdown
Owner Author

Correction response to the independent exact-head BLOCK review: #394 (review)

New exact head: cc545fe
Start/guarded remote head: fd405bd
RED commit: 7a2e0de — focused target ran 13 tests, 11 passed and 2 intended privacy regressions failed.
GREEN commit: cc545fe — focused target 13/13.

The correction rejects identity/profile/domain-like arbitrary relative-path segments, absolute/traversal/separator encodings, NUL/control/non-ASCII and unsafe fingerprint characters before assessment projection. It preserves bounded namespaced fingerprints and approved collision-safe layouts: direct, current, lo, numbered, timestamped, root-a/root-b, evidence/sccm/client, and unknown-source forms.

Verification at cc545fe:

  • cargo test --locked -p cmtraceopen-parser --test sccm_client_intake -- --nocapture — 13/13
  • cargo test --locked -p cmtraceopen-parser --test sccm_spine_contract -- --nocapture — 136/136
  • cargo test --locked -p cmtraceopen-parser — 742 tests
  • cargo clippy --locked -p cmtraceopen-parser --all-targets -- -D warnings — pass
  • cargo +1.88.0 check --locked -p cmtraceopen-parser --target wasm32-unknown-unknown — pass
  • npx tsc --noEmit — pass
  • 12 intake JSON files via jq — pass
  • Rust 1.88 scoped rustfmt, git diff --check, and clean worktree — pass
  • cargo +1.88.0 fmt --check --all — inherited 17-file non-SCCM Client: add deterministic intake, coverage, and corpus foundation #319 baseline only; both changed SCCM Client: add deterministic intake, coverage, and corpus foundation #319 files pass scoped rustfmt

Push was non-force after guarding remote/PR head fd405bd. PR remains draft/open; native #319 and real Windows acceptance remain pending.

@coderabbitai review

Please perform a fresh substantive review of exact head cc545fe, including the two-commit privacy correction. Focus on fail-closed public provenance, valid namespaced fingerprints, approved collision-safe path layouts, traversal/identity bypasses, pure Rust/wasm compatibility, and regression scope. A skipped or rate-limited response is not approval. The authenticated CodeRabbit CLI exact-range request was also attempted and returned a recoverable four-minute service rate limit before analysis; it will be retried.

@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

head='cc545fe8b8d5c56c19583556f92414df85a78fc2'
base='fd405bdf4cf527f20d3d778dedc0dc462d2f4229'
intake='crates/cmtraceopen-parser/src/sccm/client/intake.rs'
tests='crates/cmtraceopen-parser/tests/sccm_client_intake.rs'

printf '%s\n' '--- Exact commit and worktree state ---'
printf 'HEAD=%s\n' "$(git rev-parse HEAD)"
printf 'REQUESTED=%s\n' "$head"
git rev-parse "$head"
git merge-base --is-ancestor "$base" "$head"
git status --short

printf '%s\n' '--- Correction range ---'
git diff --name-status "$base" "$head"
git log --oneline --reverse "$base..$head"
git diff --check "$base" "$head"

printf '%s\n' '--- Changed-file outlines ---'
ast-grep outline "$intake" --items all --type function,struct,enum,impl
ast-grep outline "$tests" --items all --type function

printf '%s\n' '--- Privacy validation, projection, collision, and ordering locations ---'
rg -n -C 8 --glob '*.rs' \
  'validate_bundle|validate_.*(path|fingerprint)|relative_path|path_fingerprint|fingerprint|Unsupported|physical_artifacts|expected_rotated_name|sort_by|collision|Invalid' \
  "$intake" crates/cmtraceopen-parser/src/sccm

printf '%s\n' '--- Imports and platform-sensitive dependencies in intake module ---'
sed -n '1,120p' "$intake"
rg -n -C 2 --glob '*.rs' \
  'std::fs|std::path|std::env|tokio|tauri|windows|wasm_bindgen|web_sys' \
  "$intake" crates/cmtraceopen-parser/src/sccm/client

printf '%s\n' '--- Correction-range test changes ---'
git diff --minimal "$base" "$head" -- "$tests"

printf '%s\n' '--- Relevant public model contracts ---'
rg -n -C 6 --glob '*.rs' \
  'SccmClient(Intake|Unsupported)|SccmArtifact|SccmRotation|SccmCoverageState|pathFingerprint|relativePath' \
  crates/cmtraceopen-parser/src/sccm/models.rs crates/cmtraceopen-parser/src/sccm

Length of output: 2515


🏁 Script executed:

#!/bin/bash
set -euo pipefail

repo='adamgell/cmtraceopen'
pr='394'

printf '%s\n' '--- Local checkout identity ---'
git rev-parse HEAD
git show -s --format='commit=%H%nparents=%P%nsubject=%s' HEAD

printf '%s\n' '--- GitHub pull request head and base ---'
gh pr view "$pr" --repo "$repo" \
  --json number,state,isDraft,headRefName,headRefOid,baseRefName,baseRefOid,url

printf '%s\n' '--- GitHub pull request commits ---'
gh pr view "$pr" --repo "$repo" --json commits \
  --jq '.commits[] | "\(.oid)\t\(.messageHeadline)"'

printf '%s\n' '--- Requested-prefix matches in remote PR commits ---'
gh pr view "$pr" --repo "$repo" --json commits \
  --jq '.commits[].oid' | grep -i '^cc545fe8' || true

Length of output: 2079


🏁 Script executed:

#!/bin/bash
set -euo pipefail

head='cc545fe86e28d184067db31269e7aa079d2d4a65'
base='fd405bdf4cf527f20d3d778dedc0dc462d2f4229'
intake='crates/cmtraceopen-parser/src/sccm/client/intake.rs'
tests='crates/cmtraceopen-parser/tests/sccm_client_intake.rs'
models='crates/cmtraceopen-parser/src/sccm/models.rs'

printf '%s\n' '--- Correction range and changed files ---'
git diff --name-status "$base" "$head"
git diff --check "$base" "$head"
git diff --minimal "$base" "$head" -- "$intake" "$tests"

printf '%s\n' '--- Intake module outline ---'
ast-grep outline "$intake" --items all --type function,struct,enum,impl

printf '%s\n' '--- Intake implementation, first half ---'
nl -ba "$intake" | sed -n '1,430p'
printf '%s\n' '--- Intake implementation, second half ---'
nl -ba "$intake" | sed -n '431,900p'

printf '%s\n' '--- Focused test definitions and provenance cases ---'
ast-grep outline "$tests" --items all --type function
rg -n -C 12 --glob '*.rs' \
  'unsafe|provenance|relative.path|fingerprint|traversal|identity|profile|domain|control|non.ascii|collision|unknown|LocationServices' \
  "$tests"

printf '%s\n' '--- Public models and serialization contracts ---'
rg -n -C 10 --glob '*.rs' \
  'SccmRotation|SccmClient(Intake|Unsupported)|SccmArtifact|path_fingerprint|relative_path|impl Serialize' \
  "$models"

printf '%s\n' '--- All construction and serialization sites for public intake output ---'
rg -n -C 5 --glob '*.rs' \
  '\b(assess_client_intake|SccmClientIntakeBundle|SccmClientUnsupportedArtifact|to_value|to_string)\b' \
  crates/cmtraceopen-parser/src

Length of output: 11298


🏁 Script executed:

#!/bin/bash
set -euo pipefail

intake='crates/cmtraceopen-parser/src/sccm/client/intake.rs'
tests='crates/cmtraceopen-parser/tests/sccm_client_intake.rs'
models='crates/cmtraceopen-parser/src/sccm/models.rs'

printf '%s\n' '--- Intake module map ---'
ast-grep outline "$intake" --items all --type function,struct,enum

printf '%s\n' '--- Intake declarations, validation, and output construction ---'
nl -ba "$intake" | sed -n '1,260p'
nl -ba "$intake" | sed -n '260,540p'
nl -ba "$intake" | sed -n '540,780p'

printf '%s\n' '--- Public model declarations and serializers ---'
nl -ba "$models" | sed -n '240,460p'

printf '%s\n' '--- Exact references to provenance fields and output types ---'
rg -n -C 8 --glob '*.rs' \
  '\.(relative_path|path_fingerprint)|relative_path:|path_fingerprint:|SccmClientIntakeArtifact|SccmClientUnsupportedArtifact' \
  crates/cmtraceopen-parser/src crates/cmtraceopen-parser/tests

printf '%s\n' '--- Existing test helpers and full new test tail ---'
nl -ba "$tests" | sed -n '1,130p'
nl -ba "$tests" | sed -n '360,540p'

printf '%s\n' '--- Catalog group definitions and artifact-to-group matching ---'
rg -n -C 10 --glob '*.rs' \
  'CLIENT_SOURCE|client-[a-z]|declared_client_source_groups|source_group|group.*artifact|artifact.*group' \
  "$intake" crates/cmtraceopen-parser/src/sccm

Length of output: 5046


🏁 Script executed:

#!/bin/bash
set -euo pipefail

intake='crates/cmtraceopen-parser/src/sccm/client/intake.rs'
tests='crates/cmtraceopen-parser/tests/sccm_client_intake.rs'
models='crates/cmtraceopen-parser/src/sccm/models.rs'

numbered() {
  awk '{ printf "%6d  %s\n", NR, $0 }' "$1"
}

printf '%s\n' '--- Intake declarations and assessment pipeline ---'
numbered "$intake" | sed -n '1,360p'

printf '%s\n' '--- Intake validation, classification, output, and safety helpers ---'
numbered "$intake" | sed -n '360,740p'

printf '%s\n' '--- Public model declarations and serializers ---'
numbered "$models" | sed -n '240,460p'

printf '%s\n' '--- Provenance-field reads, writes, and serialization sites ---'
rg -n -C 7 --glob '*.rs' \
  '\.(relative_path|path_fingerprint)|relative_path:|path_fingerprint:|SccmClientIntakeArtifact|SccmClientUnsupportedArtifact' \
  crates/cmtraceopen-parser/src crates/cmtraceopen-parser/tests

printf '%s\n' '--- Test helper and privacy regression cases ---'
numbered "$tests" | sed -n '1,145p'
numbered "$tests" | sed -n '360,540p'

printf '%s\n' '--- Catalog definitions and artifact-to-group matching ---'
rg -n -C 10 --glob '*.rs' \
  'CLIENT_SOURCE|client-[a-z]|declared_client_source_groups|matching_groups|accepted_basenames|logical_artifact_id' \
  "$intake" crates/cmtraceopen-parser/src/sccm

Length of output: 163173


@adamgell I completed a substantive static review of verified PR head cc545fe86e28d184067db31269e7aa079d2d4a65.

The full SHA in the request does not exist on the PR. Its cc545fe8 prefix matches this verified head.

BLOCK — identity-bearing values still pass the relative-path allowlist.

is_safe_client_bundle_group on Line 659 accepts any client-<safe-path-segment>. is_safe_path_segment on Line 649 permits uppercase and lowercase ASCII letters, digits, ., _, and -. Therefore, this path is accepted:

evidence/client-RealUser/PolicyAgent.log

validate_bundle accepts the path on Lines 414-420. matching_groups then classifies PolicyAgent.log by basename only on Lines 448-460. intake_fragment copies the value into public SccmClientIntakeFragment.relative_path on Lines 475-487.

The same problem exists for root segments. is_safe_root_path_segment on Line 666 accepts arbitrary lowercase alphanumeric and hyphen values. This path is accepted and publicly projected:

evidence/client-app-enforce/root-realuser/current/AppEnforce.log

A domain-like value such as root-corp-example-test also passes.

The new tests reject identity values only when they occupy an extra path segment or use forbidden characters. They do not test identity-like values in the accepted client-* and root-* positions.

Use a bounded allowlist for client group segments. The client group values should be the exact 11 catalog identifiers plus unknown. Also constrain root labels to the approved collision namespace, or define a bounded root-label grammar that cannot carry arbitrary identity data. Add regression cases that assert InvalidRelativePath for client-RealUser, client-corp-example-test, root-realuser, and root-corp-example-test.

I also confirmed that the correction range changes only the parser intake module and its tests. The intake module imports no filesystem, Tauri, Windows, or other native I/O API. I did not run builds or tests because this sandbox does not provide compiler execution.

You are interacting with an AI system.

@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

head='cc545fe86e28d184067db31269e7aa079d2d4a65'
base='fd405bdf4cf527f20d3d778dedc0dc462d2f4229'

printf '%s\n' '--- Exact head ---'
printf 'checked_out=%s\n' "$(git rev-parse HEAD)"
printf 'requested=%s\n' "$head"
git rev-parse "${head}^{commit}"
git merge-base --is-ancestor "$base" "$head"
printf 'base_is_ancestor=yes\n'

printf '%s\n' '--- Correction-range files ---'
git diff --name-status "$base" "$head"
git diff --stat "$base" "$head"

printf '%s\n' '--- Changed-file outlines ---'
for file in \
  crates/cmtraceopen-parser/src/sccm/client/intake.rs \
  crates/cmtraceopen-parser/tests/sccm_client_intake.rs
do
  printf '\n### %s\n' "$file"
  ast-grep outline "$file" --items all --type function,struct,enum,impl,trait 2>/dev/null || true
done

printf '%s\n' '--- Correction range ---'
git diff --find-renames --minimal "$base" "$head" -- \
  crates/cmtraceopen-parser/src/sccm/client/intake.rs \
  crates/cmtraceopen-parser/tests/sccm_client_intake.rs

printf '%s\n' '--- Related public contracts and exports ---'
rg -n -C 4 --glob '*.rs' \
  'pub mod client|pub use .*intake|SccmClientIntake|SccmRotation|SccmClientIntakeError|PathFingerprint|path_fingerprint' \
  crates/cmtraceopen-parser/src/sccm

Length of output: 54422


🏁 Script executed:

#!/bin/bash
set -euo pipefail

intake='crates/cmtraceopen-parser/src/sccm/client/intake.rs'
models='crates/cmtraceopen-parser/src/sccm/models.rs'
tests='crates/cmtraceopen-parser/tests/sccm_client_intake.rs'

printf '%s\n' '--- Intake imports, public types, source catalog, and assessment ---'
sed -n '1,357p' "$intake"

printf '%s\n' '--- Intake validation, classification, ordering, and all safety helpers ---'
sed -n '358,760p' "$intake"

printf '%s\n' '--- Rotation serialization and deserialization ---'
sed -n '260,410p' "$models"

printf '%s\n' '--- Focused intake tests ---'
sed -n '1,560p' "$tests"

printf '%s\n' '--- Intake module dependencies and prohibited API indicators ---'
rg -n -C 2 --glob '*.rs' \
  '^(use|mod) |std::(fs|path|env|process|net)|tokio|tauri|reqwest|windows|wasm_bindgen|web_sys' \
  "$intake" crates/cmtraceopen-parser/src/sccm/client/mod.rs

printf '%s\n' '--- Source group declarations and group-path references ---'
rg -n -C 5 --glob '*.rs' \
  'CLIENT_SOURCE_GROUPS|ClientSourceGroupSpec|logical_artifact_id|client-policy-agent|client-app-enforce|evidence/sccm/client' \
  crates/cmtraceopen-parser/src/sccm/client "$tests"

Length of output: 87655


🏁 Script executed:

#!/bin/bash
set -euo pipefail

intake='crates/cmtraceopen-parser/src/sccm/client/intake.rs'

printf '%s\n' '--- Line-numbered public projection and validation ---'
nl -ba "$intake" | sed -n '280,445p'
nl -ba "$intake" | sed -n '475,690p'

printf '%s\n' '--- All relative-path and group/root validation references ---'
rg -n -C 3 --glob '*.rs' \
  '\b(relative_path|is_safe_relative_path|is_safe_client_bundle_group|is_safe_root_path_segment|root-[A-Za-z0-9-]+|client-[A-Za-z0-9-]+)\b' \
  crates/cmtraceopen-parser/src/sccm/client crates/cmtraceopen-parser/tests/sccm_client_intake.rs

printf '%s\n' '--- Fixture path layouts ---'
fd 'manifest.json' crates/cmtraceopen-parser/tests/fixtures/sccm/client/intake \
  -x sh -c 'echo "--- $1"; rg -n "\"relativePath\"|\"pathFingerprint\"" "$1"' sh {}

Length of output: 1196


🏁 Script executed:

#!/bin/bash
set -euo pipefail

intake='crates/cmtraceopen-parser/src/sccm/client/intake.rs'

printf '%s\n' '--- Line-numbered public projection and validation ---'
awk 'NR >= 280 && NR <= 445 { printf "%6d\t%s\n", NR, $0 }' "$intake"
awk 'NR >= 475 && NR <= 690 { printf "%6d\t%s\n", NR, $0 }' "$intake"

printf '%s\n' '--- All relative-path and group/root validation references ---'
rg -n -C 3 --glob '*.rs' \
  '\b(relative_path|is_safe_relative_path|is_safe_client_bundle_group|is_safe_root_path_segment)\b' \
  crates/cmtraceopen-parser/src/sccm/client crates/cmtraceopen-parser/tests/sccm_client_intake.rs

printf '%s\n' '--- Fixture path layouts ---'
fd 'manifest.json' crates/cmtraceopen-parser/tests/fixtures/sccm/client/intake \
  -x sh -c 'echo "--- $1"; rg -n "\"relativePath\"|\"pathFingerprint\"" "$1"' sh {}

Length of output: 56573


@adamgell I completed a substantive static review of exact head cc545fe86e28d184067db31269e7aa079d2d4a65.

I found one blocking issue.

  • P1: The new relative-path validator still accepts identity-bearing group and root segments. is_safe_client_bundle_group at crates/cmtraceopen-parser/src/sccm/client/intake.rs, Lines 659-664 accepts any safe value after client-. Therefore, evidence/client-realuser/PolicyAgent.log passes validation. is_safe_root_path_segment at Lines 666-672 similarly accepts root-realuser, so evidence/client-policy-agent/root-realuser/current/PolicyAgent.log also passes. Both values are ASCII-only and contain no traversal or separator characters. validate_bundle accepts them at Lines 414-420. intake_fragment then copies the path into the public assessment at Lines 475-487. The unsupported-artifact path also copies it at Lines 293-305.

    This bypasses the stated identity/profile protection. The new regression test rejects identity text only in extra path segments. It does not test identity text in the allowed client-* group or root-* positions.

    Replace prefix-based acceptance with a bounded allow-list for physical client group identifiers and root labels. Include the required shared client-location-services-shared identifier. Add negative regressions for both bypasses above. The assessment must return InvalidRelativePath before public projection.

I also confirmed the following by inspection:

  • The correction range contains only the two stated files.
  • The intake module has no filesystem, Tauri, Windows, process, or network dependency.
  • The public projection still excludes original_path and host.
  • Rotation serialization remains fail-closed for malformed timestamp values.
  • Path and fingerprint collision checks remain case-insensitive and deterministic.
  • LocationServices.log remains a single physical artifact with projections to both consumer groups.
  • Coverage still selects the most conservative supplied state.

I did not run builds or tests. This sandbox permits only read-only static inspection.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

adamgell added 2 commits July 31, 2026 10:07
REVIEW RED: focused client intake ran 13 tests: 12 passed and the identity-slot bypass regression failed.
@adamgell

Copy link
Copy Markdown
Owner Author

@coderabbitai review

Your exact-head blocker at #394 (comment) was valid and is corrected at exact head 06f8693.

Review RED: c9f2e6c — focused intake 12/13, with the accepted-slot identity bypass failing.
Review GREEN: 06f8693 — focused intake 13/13.

The group segment is now allowlisted from the bounded CLIENT_SOURCE_GROUPS table plus client-location-services-shared and unknown. Collision roots now accept only the committed synthetic root-a/root-b fixtures or opaque 16/64-character lowercase hexadecimal handles. Permanent regressions reject client-RealUser, client-corp-example-test, root-realuser, and root-corp-example-test while preserving shared LocationServices and opaque root-0123456789abcdef paths.

Fresh verification at 06f8693: focused 13/13; spine 136/136; full parser 742; strict Clippy; Rust 1.88 wasm32; TypeScript; 12 JSON; scoped rustfmt/diff/clean all pass. Global fmt remains only the inherited 17-file non-#319 baseline.

Please perform a fresh substantive review of exact head 06f8693 and explicitly report any remaining actionable finding. A skipped or rate-limited response is not approval. PR stays draft/open; native and real Windows acceptance remain pending.

@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

head='06f8693005c2439279133936a7023a03bf9ba514'
prior='cc545fe86e28d184067db31269e7aa079d2d4a65'
intake='crates/cmtraceopen-parser/src/sccm/client/intake.rs'
tests='crates/cmtraceopen-parser/tests/sccm_client_intake.rs'
models='crates/cmtraceopen-parser/src/sccm/models.rs'

printf '%s\n' '--- Exact PR and commit identity ---'
printf 'checked_out=%s\n' "$(git rev-parse HEAD)"
git rev-parse "${head}^{commit}"
git merge-base --is-ancestor "$prior" "$head" && echo 'prior_is_ancestor=yes'
gh pr view 394 --repo adamgell/cmtraceopen \
  --json state,isDraft,headRefOid,baseRefOid,url \
  --jq '"pr=\(.url) state=\(.state) draft=\(.isDraft) head=\(.headRefOid) base=\(.baseRefOid)"'

printf '%s\n' '--- Correction range ---'
git log --oneline --reverse "${prior}..${head}"
git diff --name-status "$prior" "$head"
git diff --check "$prior" "$head"
git diff --find-renames --minimal "$prior" "$head" -- "$intake" "$tests"

printf '%s\n' '--- Changed-file maps ---'
ast-grep outline "$intake" --items all --type function,struct,enum,impl
ast-grep outline "$tests" --items all --type function

printf '%s\n' '--- Validation, classification, projection, collision, and ordering ---'
nl -ba "$intake" | sed -n '1,780p'

printf '%s\n' '--- Public model contracts and serializers ---'
nl -ba "$models" | sed -n '240,470p'

printf '%s\n' '--- Focused privacy, path, collision, and ordering tests ---'
rg -n -C 16 --glob '*.rs' \
  'privacy|identity|profile|domain|relative.path|fingerprint|root-|client-|LocationServices|collision|ordering|rotation|unsupported|InvalidRelativePath' \
  "$tests"

printf '%s\n' '--- Intake call sites and platform-sensitive dependencies ---'
rg -n -C 5 --glob '*.rs' \
  '\b(assess_client_intake|SccmClientIntakeBundle|SccmClientUnsupportedArtifact)\b' \
  crates/cmtraceopen-parser/src crates/cmtraceopen-parser/tests
rg -n -C 2 --glob '*.rs' \
  'std::(fs|path|env|process|net)|tokio|tauri|reqwest|windows|wasm_bindgen|web_sys' \
  "$intake" crates/cmtraceopen-parser/src/sccm/client/mod.rs || true

Length of output: 6046


🏁 Script executed:

#!/bin/bash
set -euo pipefail

head='06f8693005c2439279133936a7023a03bf9ba514'
intake='crates/cmtraceopen-parser/src/sccm/client/intake.rs'
tests='crates/cmtraceopen-parser/tests/sccm_client_intake.rs'
models='crates/cmtraceopen-parser/src/sccm/models.rs'

test "$(git rev-parse HEAD)" = "$head"

printf '%s\n' '--- Intake and test maps ---'
ast-grep outline "$intake" --items all --type function,struct,enum
ast-grep outline "$tests" --items all --type function

printf '%s\n' '--- Intake catalog and assessment pipeline ---'
nl -ba "$intake" | sed -n '1,360p'
printf '%s\n' '--- Intake validation, classification, projection, ordering, and safety helpers ---'
nl -ba "$intake" | sed -n '360,780p'

printf '%s\n' '--- Public models and serializers used by intake ---'
nl -ba "$models" | sed -n '240,470p'

printf '%s\n' '--- Focused test helpers and all privacy-related test bodies ---'
nl -ba "$tests" | sed -n '1,160p'
nl -ba "$tests" | sed -n '340,550p'

printf '%s\n' '--- All provenance field reads and writes ---'
rg -n -C 7 --glob '*.rs' \
  '\.(relative_path|path_fingerprint|original_path|host)|relative_path:|path_fingerprint:|original_path:|host:' \
  crates/cmtraceopen-parser/src/sccm crates/cmtraceopen-parser/tests/sccm_client_intake.rs

printf '%s\n' '--- Intake API use and platform-sensitive dependencies ---'
rg -n -C 5 --glob '*.rs' \
  '\b(assess_client_intake|SccmClientIntakeBundle|SccmClientUnsupportedArtifact)\b' \
  crates/cmtraceopen-parser/src crates/cmtraceopen-parser/tests
rg -n -C 2 --glob '*.rs' \
  'std::(fs|path|env|process|net)|tokio|tauri|reqwest|windows|wasm_bindgen|web_sys' \
  "$intake" crates/cmtraceopen-parser/src/sccm/client/mod.rs || true

Length of output: 6853


🏁 Script executed:

#!/bin/bash
set -euo pipefail

head='06f8693005c2439279133936a7023a03bf9ba514'
intake='crates/cmtraceopen-parser/src/sccm/client/intake.rs'
tests='crates/cmtraceopen-parser/tests/sccm_client_intake.rs'
models='crates/cmtraceopen-parser/src/sccm/models.rs'

test "$(git rev-parse HEAD)" = "$head"

show_lines() {
  awk -v start="$2" -v end="$3" \
    'NR >= start && NR <= end { printf "%6d\t%s\n", NR, $0 }' "$1"
}

printf '%s\n' '--- Intake catalog and assessment pipeline ---'
show_lines "$intake" 1 357
printf '%s\n' '--- Intake validation, matching, projection, ordering, and path safety ---'
show_lines "$intake" 358 740

printf '%s\n' '--- Public model contracts and serializers ---'
show_lines "$models" 240 470

printf '%s\n' '--- Test helpers and privacy/path regressions ---'
show_lines "$tests" 1 160
show_lines "$tests" 240 550

printf '%s\n' '--- All public provenance reads and writes ---'
rg -n -C 7 --glob '*.rs' \
  '\.(relative_path|path_fingerprint|original_path|host)|relative_path:|path_fingerprint:|original_path:|host:' \
  crates/cmtraceopen-parser/src/sccm crates/cmtraceopen-parser/tests/sccm_client_intake.rs

printf '%s\n' '--- Intake API use and platform-sensitive dependencies ---'
rg -n -C 5 --glob '*.rs' \
  '\b(assess_client_intake|SccmClientIntakeBundle|SccmClientUnsupportedArtifact)\b' \
  crates/cmtraceopen-parser/src crates/cmtraceopen-parser/tests
rg -n -C 2 --glob '*.rs' \
  'std::(fs|path|env|process|net)|tokio|tauri|reqwest|windows|wasm_bindgen|web_sys' \
  "$intake" crates/cmtraceopen-parser/src/sccm/client/mod.rs || true

Length of output: 131924


@adamgell I completed a fresh static review of exact head 06f8693005c2439279133936a7023a03bf9ba514.

I found one remaining actionable issue.

  • P1: path_fingerprint still permits identity-bearing values. is_safe_path_identity at crates/cmtraceopen-parser/src/sccm/client/intake.rs, Lines 612-616 accepts any nonempty colon-separated sequence of generic safe segments. is_safe_path_segment accepts lowercase letters, digits, ., _, and - at Lines 649-657. Therefore, values such as realuser, corp-example-test, or domain-example-test pass validation. assess_client_intake then copies path_fingerprint into both public supported fragments at Lines 475-487 and public unsupported artifacts at Lines 293-305.

    The new fingerprint regressions reject controls, non-ASCII characters, separators, %, @, and spaces. They do not reject identity-like values that use the accepted character set. This leaves the same public-provenance boundary open through pathFingerprint.

    Replace the generic segment grammar with a bounded fingerprint namespace allowlist. For example, accept only documented schemes and their bounded payload grammar. Add regressions that require InvalidPathFingerprint for realuser, corp-example-test, and equivalent identity-like values. Keep the committed valid namespaced forms, such as sha256:<hex> and the defined synthetic forms.

I confirmed the prior relative-path finding is fixed.

  • client-* path groups now use the CLIENT_SOURCE_GROUPS allowlist plus client-location-services-shared and unknown.
  • Collision root labels now allow only root-a, root-b, or 16/64-character lowercase hexadecimal handles.
  • The new tests reject the prior client-RealUser, client-corp-example-test, root-realuser, and root-corp-example-test bypasses.
  • The correction range changes only the intake module and its focused tests.
  • The intake module has no filesystem, Tauri, Windows, process, or network dependency.
  • The module retains the fail-closed timestamp serializer gate, deterministic fragment ordering, collision checks, and the single-capture LocationServices.log projection.

I did not run builds or tests. This review environment supports read-only static inspection only.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

CODERABBIT RED: focused client intake ran 13 tests: 12 passed and the impossible timestamp regression failed.

@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: 1

🤖 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/tests/sccm_client_intake.rs`:
- Around line 394-411: Extend
identity_bearing_relative_paths_fail_before_public_projection with cases where
client-group and root-label namespace segments contain arbitrary identity
values, including client-realuser/current/PolicyAgent.log,
client-app-enforce/root-realuser/current/AppEnforce.log, and the shared
LocationServices.log path. Replace prefix-based acceptance with bounded
allowlists for client group identifiers and root labels, apply the same
validation to LocationServices.log, and assert InvalidRelativePath for every
rejected path.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 93694b73-d731-444a-a1ef-cf6f07e4d0d5

📥 Commits

Reviewing files that changed from the base of the PR and between a8a367c and cc545fe.

📒 Files selected for processing (4)
  • crates/cmtraceopen-parser/src/sccm/client/intake.rs
  • crates/cmtraceopen-parser/src/sccm/client/mod.rs
  • crates/cmtraceopen-parser/src/sccm/mod.rs
  • crates/cmtraceopen-parser/tests/sccm_client_intake.rs

Comment thread crates/cmtraceopen-parser/tests/sccm_client_intake.rs
@adamgell

Copy link
Copy Markdown
Owner Author

@coderabbitai review

Please perform a substantive exact-head review of 54470563724af20de87aeca5e5a50e4090de5091 against base fd405bdf4cf527f20d3d778dedc0dc462d2f4229 after the test-first privacy corrections. Focus on public provenance path/fingerprint fail-closed behavior, bounded namespaces, timestamp value validation, deterministic serialization, and accidental identity leakage. The local CLI connected but is quota-deferred for 35 minutes; that deferral is not being treated as approval.

@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

repo='adamgell/cmtraceopen'
pr='394'
head='54470563724af20de87aeca5e5a50e4090de5091'
base='fd405bdf4cf527f20d3d778dedc0dc462d2f4229'
intake='crates/cmtraceopen-parser/src/sccm/client/intake.rs'
tests='crates/cmtraceopen-parser/tests/sccm_client_intake.rs'
models='crates/cmtraceopen-parser/src/sccm/models.rs'

printf '%s\n' '--- Commit and PR identity ---'
printf 'checked_out=%s\n' "$(git rev-parse HEAD)"
printf 'requested=%s\n' "$head"
git rev-parse "${head}^{commit}"
git merge-base --is-ancestor "$base" "$head" && echo 'base_is_ancestor=yes'
gh pr view "$pr" --repo "$repo" \
  --json state,isDraft,headRefOid,baseRefOid,url \
  --jq '"pr=\(.url) state=\(.state) draft=\(.isDraft) head=\(.headRefOid) base=\(.baseRefOid)"'

printf '%s\n' '--- Review range ---'
git log --oneline --reverse "${base}..${head}"
git diff --name-status "$base" "$head"
git diff --check "$base" "$head"
git diff --find-renames --minimal "$base" "$head" -- "$intake" "$tests"

printf '%s\n' '--- Relevant file outlines ---'
ast-grep outline "$intake" --items all --type function,struct,enum,impl
ast-grep outline "$tests" --items all --type function
ast-grep outline "$models" --items all --type function,struct,enum,impl

printf '%s\n' '--- Intake implementation: public types, validation, projection, and ordering ---'
nl -ba "$intake" | sed -n '1,800p'

printf '%s\n' '--- Rotation model serialization contract ---'
nl -ba "$models" | sed -n '240,470p'

printf '%s\n' '--- Focused provenance, fingerprint, path, rotation, collision, and ordering tests ---'
rg -n -C 14 --glob '*.rs' \
  'provenance|privacy|identity|fingerprint|relative.path|Invalid(PathFingerprint|RelativePath|Rotation)|Timestamped|timestamp|collision|ordering|LocationServices|unsupported' \
  "$tests"

printf '%s\n' '--- All provenance reads and writes in production code ---'
rg -n -C 7 --glob '*.rs' \
  '\.(relative_path|path_fingerprint|original_path|host)|relative_path:|path_fingerprint:|original_path:|host:' \
  crates/cmtraceopen-parser/src/sccm

printf '%s\n' '--- Platform-sensitive dependencies in intake module ---'
rg -n -C 2 --glob '*.rs' \
  'std::(fs|path|env|process|net)|tokio|tauri|reqwest|windows|wasm_bindgen|web_sys' \
  "$intake" crates/cmtraceopen-parser/src/sccm/client/mod.rs || true

Length of output: 13520


🏁 Script executed:

#!/bin/bash
set -euo pipefail

head='54470563724af20de87aeca5e5a50e4090de5091'
intake='crates/cmtraceopen-parser/src/sccm/client/intake.rs'
tests='crates/cmtraceopen-parser/tests/sccm_client_intake.rs'
models='crates/cmtraceopen-parser/src/sccm/models.rs'

test "$(git rev-parse HEAD)" = "$head"

printf '%s\n' '--- Intake map ---'
ast-grep outline "$intake" --items all --type function,struct,enum

printf '%s\n' '--- Focused-test map ---'
ast-grep outline "$tests" --items all --type function

printf '%s\n' '--- Validation and public-projection pipeline ---'
nl -ba "$intake" | sed -n '250,760p'

printf '%s\n' '--- Full path and fingerprint validation context ---'
rg -n -C 18 --glob '*.rs' \
  'fn validate_bundle|is_safe_path_identity|is_safe_relative_path|is_safe_path_segment|path_fingerprint|relative_path|InvalidPathFingerprint|InvalidRelativePath' \
  "$intake"

printf '%s\n' '--- Classification, collision checks, output construction, and deterministic ordering ---'
rg -n -C 16 --glob '*.rs' \
  'matching_groups|collision|sort_by|cmp\(|intake_fragment|unsupported|physical_artifacts|fragments|expected_rotated_name' \
  "$intake"

printf '%s\n' '--- Rotation serialization and canonical-timestamp implementation ---'
rg -n -C 15 --glob '*.rs' \
  'SccmRotation|impl Serialize|serialize|is_canonical_rotation_timestamp|Timestamped' \
  "$models" crates/cmtraceopen-parser/src/sccm

printf '%s\n' '--- Full focused privacy and timestamp test bodies ---'
nl -ba "$tests" | sed -n '250,560p'

printf '%s\n' '--- Path-fingerprint fixture values and all production construction sites ---'
rg -n -C 5 --glob '*.rs' \
  'path_fingerprint:|path_fingerprint\s*=|pathFingerprint|synthetic:|sha256:' \
  crates/cmtraceopen-parser/src crates/cmtraceopen-parser/tests

printf '%s\n' '--- Native or platform-dependent intake dependencies ---'
rg -n -C 2 --glob '*.rs' \
  'std::(fs|path|env|process|net)|tokio|tauri|reqwest|windows|wasm_bindgen|web_sys' \
  "$intake" crates/cmtraceopen-parser/src/sccm/client/mod.rs || true

Length of output: 7148


🏁 Script executed:

#!/bin/bash
set -euo pipefail

head='54470563724af20de87aeca5e5a50e4090de5091'
intake='crates/cmtraceopen-parser/src/sccm/client/intake.rs'
tests='crates/cmtraceopen-parser/tests/sccm_client_intake.rs'
models='crates/cmtraceopen-parser/src/sccm/models.rs'

test "$(git rev-parse HEAD)" = "$head"

printf '%s\n' '--- Validation, classification, projection, collision, and ordering ---'
sed -n '281,710p' "$intake" | awk '{ printf "%6d  %s\n", NR + 280, $0 }'

printf '%s\n' '--- Focused regression bodies ---'
sed -n '285,525p' "$tests" | awk '{ printf "%6d  %s\n", NR + 284, $0 }'

printf '%s\n' '--- Rotation serialization and timestamp validator ---'
rg -n -C 18 --glob '*.rs' \
  'enum SccmRotation|impl Serialize for SccmRotation|fn is_canonical_rotation_timestamp|is_canonical_rotation_timestamp|Timestamped' \
  "$models" crates/cmtraceopen-parser/src/sccm/rotation.rs crates/cmtraceopen-parser/src/sccm

printf '%s\n' '--- Every path-fingerprint validator call and public-field projection ---'
rg -n -C 10 --glob '*.rs' \
  'is_safe_path_identity\(|InvalidPathFingerprint|path_fingerprint: source\.path_fingerprint|path_fingerprint:.*path_fingerprint' \
  "$intake"

printf '%s\n' '--- All committed fingerprint literals in fixtures and focused tests ---'
rg -n -C 2 --glob '*.json' --glob '*.rs' \
  '"pathFingerprint"|path_fingerprint\s*=|path_fingerprint:|synthetic:|sha256:' \
  crates/cmtraceopen-parser/tests/fixtures/sccm/client/intake "$tests"

printf '%s\n' '--- Intake import list and prohibited dependencies ---'
sed -n '1,24p' "$intake"
rg -n -C 2 --glob '*.rs' \
  'std::(fs|path|env|process|net)|tokio|tauri|reqwest|windows|wasm_bindgen|web_sys' \
  "$intake" crates/cmtraceopen-parser/src/sccm/client/mod.rs || true

Length of output: 112087


@adamgell I completed a substantive static review of exact head 54470563724af20de87aeca5e5a50e4090de5091 against fd405bdf4cf527f20d3d778dedc0dc462d2f4229.

I found one actionable blocking issue.

  • P1: path_fingerprint still accepts arbitrary identity-bearing ASCII values. In crates/cmtraceopen-parser/src/sccm/client/intake.rs, Lines 613-617, is_safe_path_identity accepts any nonempty colon-separated sequence of generic safe segments. is_safe_path_segment at Lines 650-658 permits letters, digits, ., _, and -. Therefore, values such as realuser, corp-example-test, domain-example-test, and synthetic:realuser pass validate_bundle at Lines 407-413. The assessment then copies the value into public supported fragments at Lines 476-488 and unsupported artifacts at Lines 294-305.

    The existing negative tests at Lines 434-462 reject controls, non-ASCII text, separators, %, @, and whitespace. They do not reject identity-like values that use the accepted character set.

    Replace the generic grammar with a bounded fingerprint namespace allowlist. Preserve documented forms such as the existing synthetic-*, synthetic:..., and sha256:<hex> forms. Define the accepted payload grammar for each namespace. Add regressions that require InvalidPathFingerprint for realuser, corp-example-test, domain-example-test, and synthetic:realuser.

I also confirmed the following:

  • The relative-path correction is effective. Client groups use the declared group list plus client-location-services-shared and unknown.
  • Collision roots accept only root-a, root-b, or 16/64-character lowercase hexadecimal handles.
  • The new timestamp-path check calls is_canonical_rotation_timestamp. It rejects impossible values such as 20241340-296199.
  • validate_bundle serializes each SccmRotation before classification. SccmRotation::serialize rejects noncanonical timestamp values.
  • Fragment ordering is deterministic. It orders by rotation rank and value, then fingerprint, basename, and artifact ID.
  • Public output does not copy original_path or host.
  • The intake module has no filesystem, process, network, Tauri, Windows, or other native dependency.

I did not run builds or tests. This environment supports read-only static inspection only.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@adamgell
adamgell requested a review from Copilot August 2, 2026 02:58
@coderabbitai

coderabbitai Bot commented Aug 2, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.

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

Copilot reviewed 16 out of 16 changed files in this pull request and generated no new comments.

@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: 2

🧹 Nitpick comments (6)
crates/cmtraceopen-parser/src/sccm/client/intake.rs (2)

1455-1459: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider rejecting an empty value in is_lowercase_hex.

is_lowercase_hex("") returns true, because all on an empty iterator is true. Both current callers gate on an exact length first, so no defect exists today. A future caller that omits the length gate would silently accept an empty handle. An explicit emptiness guard removes that trap.

🛡️ Proposed hardening
 fn is_lowercase_hex(value: &str) -> bool {
-    value
+    !value.is_empty()
+        && value
         .bytes()
         .all(|byte| byte.is_ascii_digit() || matches!(byte, b'a'..=b'f'))
 }
🤖 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/sccm/client/intake.rs` around lines 1455 -
1459, Update is_lowercase_hex to return false when value is empty, while
preserving the existing lowercase hexadecimal validation for non-empty values.

243-443: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚖️ Poor tradeoff

Consider guarding the wire mirrors against field drift.

Each public projection type has a hand-written wire twin plus two From impls. If a field is added to SccmClientIntakeFragment and not to SccmClientIntakeFragmentWire, the field disappears from the serialized assessment without any compile error. The From<SccmClientIntakeFragmentWire> direction fails to compile, but the From<&SccmClientIntakeFragment> direction does not.

A destructuring pattern in the From<&T> impls makes the omission a compile error.

♻️ Example for one impl
 impl From<&SccmClientIntakeFragment> for SccmClientIntakeFragmentWire {
     fn from(fragment: &SccmClientIntakeFragment) -> Self {
+        let SccmClientIntakeFragment {
+            artifact_id,
+            basename,
+            rotation,
+            coverage,
+            path_fingerprint,
+            rotation_lineage,
+            relative_path,
+            fragment_complete,
+            configmgr_version,
+            collected_at_utc,
+            encoding,
+        } = fragment;
         Self {
-            artifact_id: fragment.artifact_id.clone(),
+            artifact_id: artifact_id.clone(),
🤖 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/sccm/client/intake.rs` around lines 243 - 443,
Update the `From<&SccmClientIntakeFragment>` and equivalent `From<&...>`
wire-conversion implementations to destructure their source public types before
constructing the wire mirrors, so adding a source field without updating the
wire type causes a compile error. Apply this to `SccmClientIntakeGroup`,
`SccmClientIntakeCoverageGap`, `SccmClientUnsupportedArtifact`, and
`SccmClientIntakeAssessment`, preserving the existing field mappings.
crates/cmtraceopen-parser/tests/fixtures/sccm/client/intake/collision/expected.json (1)

174-188: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

The unique-contents claim is not pinned for this fixture pair.

The fixture README states that the two AppEnforce.log files keep unique contents. Both provenance entries here declare bytesCopied: 180 and neither declares a sha256. The fixture test only compares file length when sha256 is absent, so two byte-identical evidence files would still pass. Adding a sha256 to both entries pins the uniqueness that the README claims.

This is optional. The distinct pathFingerprint and relativePath values already prove the collision behavior that the scenario targets.

🤖 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/sccm/client/intake/collision/expected.json`
around lines 174 - 188, Add the correct sha256 value to both artifactProvenance
entries for fixture-collision-app-enforce-root-a-current and
fixture-collision-app-enforce-root-b-current in nativeDesignPending, preserving
their existing metadata and ensuring the hashes reflect their distinct file
contents.
crates/cmtraceopen-parser/src/sccm/mod.rs (1)

2-2: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider whether the double public path is intended.

Line 2 makes client public and line 13 glob re-exports it. Every intake item therefore resolves at both sccm::client::X and sccm::X. The PR objectives describe the API as sccm::client::intake, which suggests the module path is the intended one.

A glob re-export also couples this line to the sibling server module: any future name shared by client::* and server::* becomes an ambiguity error here. Keeping pub mod client; without the glob, or re-exporting named items, avoids that coupling.

Also applies to: 13-13

🤖 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/sccm/mod.rs` at line 2, Remove the glob
re-export of client items from the SCCM module, keeping client publicly
accessible through sccm::client and preserving the intended sccm::client::intake
API. Update the module declarations around pub mod client and the corresponding
re-export to avoid collisions with server names.
crates/cmtraceopen-parser/src/sccm/findings.rs (1)

2342-2355: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

The second normalization of each component is redundant.

Line 2338 splits the stem on every character that is not ASCII alphanumeric and not _. Each resulting component therefore already contains only characters that normalize_catalog_identity retains. The call at line 2340 only lowercases. Replacing it with a direct lowercase makes the intent explicit and avoids implying that further stripping can occur.

This is a readability point only. The current behavior is correct.

🤖 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/sccm/findings.rs` around lines 2342 - 2355, In
the basename component construction immediately before the ranges extension,
replace the repeated normalize_catalog_identity call with direct lowercasing of
each already-sanitized component. Preserve the existing component splitting and
matching behavior; this is only a readability change.
crates/cmtraceopen-parser/tests/sccm_spine_contract.rs (1)

3936-3972: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

Match the deserializer error variant exactly. Replace the Debug substring check with a structured or exact variant comparison. A future variant named InvalidArtifactRequestReasonLength could satisfy the current contains check.

🤖 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/sccm_spine_contract.rs` around lines 3936 -
3972, Update the deserializer assertion in the cases loop to compare the
returned error against the expected error variant structurally or exactly,
rather than matching a Debug-format substring. Preserve the existing validation
checks and ensure similarly named variants such as
InvalidArtifactRequestReasonLength cannot be accepted accidentally.
🤖 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/tests/fixtures/sccm/client/README.md`:
- Around line 48-53: Clarify the noncapture-artifact rule in the fixture README
by explicitly stating that “bytesCopied: 0” and a null relative path apply to
manifest.json; note that such artifacts are omitted from expected.json’s
nativeDesignPending.artifactProvenance.

In `@crates/cmtraceopen-parser/tests/sccm_client_intake.rs`:
- Around line 1302-1307: Update the assertion message in the client-content
group coverage test to describe the actual severity ordering: Capped outranks
Absent, which outranks Captured. Leave the assertions and coverage
implementation unchanged.

---

Nitpick comments:
In `@crates/cmtraceopen-parser/src/sccm/client/intake.rs`:
- Around line 1455-1459: Update is_lowercase_hex to return false when value is
empty, while preserving the existing lowercase hexadecimal validation for
non-empty values.
- Around line 243-443: Update the `From<&SccmClientIntakeFragment>` and
equivalent `From<&...>` wire-conversion implementations to destructure their
source public types before constructing the wire mirrors, so adding a source
field without updating the wire type causes a compile error. Apply this to
`SccmClientIntakeGroup`, `SccmClientIntakeCoverageGap`,
`SccmClientUnsupportedArtifact`, and `SccmClientIntakeAssessment`, preserving
the existing field mappings.

In `@crates/cmtraceopen-parser/src/sccm/findings.rs`:
- Around line 2342-2355: In the basename component construction immediately
before the ranges extension, replace the repeated normalize_catalog_identity
call with direct lowercasing of each already-sanitized component. Preserve the
existing component splitting and matching behavior; this is only a readability
change.

In `@crates/cmtraceopen-parser/src/sccm/mod.rs`:
- Line 2: Remove the glob re-export of client items from the SCCM module,
keeping client publicly accessible through sccm::client and preserving the
intended sccm::client::intake API. Update the module declarations around pub mod
client and the corresponding re-export to avoid collisions with server names.

In
`@crates/cmtraceopen-parser/tests/fixtures/sccm/client/intake/collision/expected.json`:
- Around line 174-188: Add the correct sha256 value to both artifactProvenance
entries for fixture-collision-app-enforce-root-a-current and
fixture-collision-app-enforce-root-b-current in nativeDesignPending, preserving
their existing metadata and ensuring the hashes reflect their distinct file
contents.

In `@crates/cmtraceopen-parser/tests/sccm_spine_contract.rs`:
- Around line 3936-3972: Update the deserializer assertion in the cases loop to
compare the returned error against the expected error variant structurally or
exactly, rather than matching a Debug-format substring. Preserve the existing
validation checks and ensure similarly named variants such as
InvalidArtifactRequestReasonLength cannot be accepted accidentally.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 73c57035-cf09-46b6-8555-916dbb4480fb

📥 Commits

Reviewing files that changed from the base of the PR and between 34c3aba and 5be9b95.

📒 Files selected for processing (16)
  • crates/cmtraceopen-parser/src/sccm/catalog.rs
  • crates/cmtraceopen-parser/src/sccm/client/intake.rs
  • crates/cmtraceopen-parser/src/sccm/client/mod.rs
  • crates/cmtraceopen-parser/src/sccm/findings.rs
  • crates/cmtraceopen-parser/src/sccm/mod.rs
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/README.md
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/intake/access-denied/expected.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/intake/capped/expected.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/intake/collision/expected.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/intake/complete/expected.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/intake/missing-root/expected.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/intake/rotations/expected.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/intake/rotations/manifest.json
  • crates/cmtraceopen-parser/tests/sccm_client_intake.rs
  • crates/cmtraceopen-parser/tests/sccm_spine_contract.rs
  • docs/sccm/preparation/issue-319-client-intake.md

Comment thread crates/cmtraceopen-parser/tests/fixtures/sccm/client/README.md Outdated
Comment thread crates/cmtraceopen-parser/tests/sccm_client_intake.rs
@adamgell

adamgell commented Aug 2, 2026

Copy link
Copy Markdown
Owner Author

CodeRabbit feedback addressed

Validated both exact-head comments independently and corrected the two wording defects in commit 05d4bf0:

  • clarified that zero-byte/null-path noncapture fields belong to manifest.json and are omitted from the expected native provenance projection;
  • corrected the coverage assertion rationale to the actual severity order.

Verification: focused client-intake suite 47/47, scoped Rust 1.88 rustfmt, and git diff --check passed. Global cargo fmt --check --all still reports the pre-existing unrelated formatting baseline; neither edited file contributes to it.

A fresh exact-head CodeRabbit cycle is now required before this draft can move forward.

@adamgell

adamgell commented Aug 2, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai full review

@adamgell
adamgell requested a review from Copilot August 2, 2026 03:10
@coderabbitai

coderabbitai Bot commented Aug 2, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.

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

Copilot reviewed 16 out of 16 changed files in this pull request and generated no new comments.

Suppressed comments (1)

crates/cmtraceopen-parser/src/sccm/client/intake.rs:333

  • SccmClientIntakeCoverageGapWire.artifact_id is configured with skip_serializing_if = "Option::is_none", so artifactId will be omitted (not serialized as null) for group-level gaps where there is no specific artifact. The fixture oracles currently include "artifactId": null for these entries, and other optional gap/fragment fields are serialized as explicit null, so omitting this one makes the public JSON shape inconsistent and harder for downstream consumers to rely on.

Consider removing skip_serializing_if (keep default) so the field is always present and round-trips cleanly as null when absent.

struct SccmClientIntakeCoverageGapWire {
    logical_artifact_id: String,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    artifact_id: Option<String>,
    role: SccmRole,
    coverage: SccmCoverageState,
    reason: String,
}

@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.

🧹 Nitpick comments (3)
crates/cmtraceopen-parser/tests/sccm_spine_contract.rs (2)

3887-3933: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add a rejection case for a single component of the multi-dot basename.

The new range logic in crates/cmtraceopen-parser/src/sccm/findings.rs splits client.msi into the components client and msi, then authorizes the token window for each. The five cases here cover an unknown multi-dot basename, a mismatched logical ID, a mismatched role, a glob, and unbounded language. No case asserts that a bare component is still rejected.

A case such as clientMsi with the reason Collect the complete client.log file. pins the boundary that the component split creates.

💚 Proposed additional case
         (
             "unknown multi-dot basename",
             finding_request(
                 "clientMsi",
                 SccmRole::Client,
                 "Collect the complete client.unknown.log file.",
             ),
             SccmFindingValidationError::InvalidArtifactRequestReason,
         ),
+        (
+            "bare component of the multi-dot basename",
+            finding_request(
+                "clientMsi",
+                SccmRole::Client,
+                "Collect the complete client.log file.",
+            ),
+            SccmFindingValidationError::InvalidArtifactRequestReason,
+        ),
🤖 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/sccm_spine_contract.rs` around lines 3887 -
3933, Add a rejection case to the cases table for finding_request("clientMsi",
SccmRole::Client, "Collect the complete client.log file.") and expect
SccmFindingValidationError::InvalidArtifactRequestReason, covering rejection of
a bare component from the multi-dot basename.

3959-3971: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider asserting the deserializer error by value.

The builder check at Line 3946 and the direct validation check at Line 3952 compare expected_error by value. The deserializer check compares a substring of the error text against the Debug spelling of the variant. That assertion is weaker. It passes if the serde error text happens to contain the variant name for another reason, and it breaks if the error text format changes.

The current form still fails when deserialization succeeds, so there is a safe fallback. Treat this as a test-precision improvement.

🤖 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/sccm_spine_contract.rs` around lines 3959 -
3971, Update the deserializer assertion in the SccmFinding test to compare the
returned error against expected_error by value, matching the builder and direct
validation checks. Keep successful deserialization as a failure, and avoid
relying on formatted error text or Debug-string substring matching.
crates/cmtraceopen-parser/src/sccm/catalog.rs (1)

632-634: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider moving CCM-record eligibility onto CatalogSpec.

catalog_entry_uses_ccm_records decides eligibility by matching logical_name against a string literal list. The fact then lives away from the catalog entry that owns it. A future rename of clientMsi or reportingEvents silently re-enables raw CCM handling for that entry.

The spine contract test currently pins the expected tuples, so a rename would fail the suite. This is therefore a readability and locality improvement, not a defect.

An alternative is a uses_ccm_records: bool field on CatalogSpec, set per entry.

🤖 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/sccm/catalog.rs` around lines 632 - 634, Move
CCM-record eligibility into CatalogSpec by adding an appropriate method or field
that defines whether each catalog entry uses CCM records, initialized for
clientMsi and reportingEvents as ineligible. Update
catalog_entry_uses_ccm_records to delegate to that CatalogSpec-owned definition
instead of matching logical_name string literals, while preserving the existing
tuple expectations and behavior.
🤖 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.

Nitpick comments:
In `@crates/cmtraceopen-parser/src/sccm/catalog.rs`:
- Around line 632-634: Move CCM-record eligibility into CatalogSpec by adding an
appropriate method or field that defines whether each catalog entry uses CCM
records, initialized for clientMsi and reportingEvents as ineligible. Update
catalog_entry_uses_ccm_records to delegate to that CatalogSpec-owned definition
instead of matching logical_name string literals, while preserving the existing
tuple expectations and behavior.

In `@crates/cmtraceopen-parser/tests/sccm_spine_contract.rs`:
- Around line 3887-3933: Add a rejection case to the cases table for
finding_request("clientMsi", SccmRole::Client, "Collect the complete client.log
file.") and expect SccmFindingValidationError::InvalidArtifactRequestReason,
covering rejection of a bare component from the multi-dot basename.
- Around line 3959-3971: Update the deserializer assertion in the SccmFinding
test to compare the returned error against expected_error by value, matching the
builder and direct validation checks. Keep successful deserialization as a
failure, and avoid relying on formatted error text or Debug-string substring
matching.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 4995bdad-71c3-44a5-a8fd-121492122b6f

📥 Commits

Reviewing files that changed from the base of the PR and between 34c3aba and 05d4bf0.

📒 Files selected for processing (16)
  • crates/cmtraceopen-parser/src/sccm/catalog.rs
  • crates/cmtraceopen-parser/src/sccm/client/intake.rs
  • crates/cmtraceopen-parser/src/sccm/client/mod.rs
  • crates/cmtraceopen-parser/src/sccm/findings.rs
  • crates/cmtraceopen-parser/src/sccm/mod.rs
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/README.md
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/intake/access-denied/expected.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/intake/capped/expected.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/intake/collision/expected.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/intake/complete/expected.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/intake/missing-root/expected.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/intake/rotations/expected.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/intake/rotations/manifest.json
  • crates/cmtraceopen-parser/tests/sccm_client_intake.rs
  • crates/cmtraceopen-parser/tests/sccm_spine_contract.rs
  • docs/sccm/preparation/issue-319-client-intake.md

@adamgell

adamgell commented Aug 2, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai full review

@adamgell

adamgell commented Aug 2, 2026

Copy link
Copy Markdown
Owner Author

Exact-head review adjudication

Current head: 269e713865cf51d578ef7edc7f0fa901163d0d90

Validated the latest CodeRabbit nitpicks and Copilot suppressed observation against the contracts:

  • Added the missing client.msi.log bare-component rejection case.
  • Replaced substring matching of the serde validation variant with an exact full error message comparison. serde_json does not expose the inner validation enum by value, so exact message equality is the strongest available public-boundary assertion without changing the API.
  • Added RED group_level_coverage_gaps_serialize_an_explicit_null_artifact_id; it failed because artifactId was omitted. The wire now emits explicit null, matching the committed fixture oracle and the other optional gap fields.
  • Deferred the suggested CatalogSpec eligibility refactor: current behavior is correct and already pinned by exact catalog tests; widening this SCCM Client: add deterministic intake, coverage, and corpus foundation #319 slice into a full shared-catalog layout change would be unrelated churn.

Verification at this exact head:

  • RED reproduced for omitted group-level artifactId; focused GREEN passed.
  • Client intake: 48/48.
  • SCCM spine: 161/161.
  • Full cmtraceopen-parser suite: passed.
  • Strict parser Clippy: passed.
  • Rust 1.88 wasm32 check: passed.
  • TypeScript: passed.
  • Scoped Rust 1.88 rustfmt, intake JSON parse, and git diff --check: passed.

Fresh exact-head CodeRabbit, Copilot, and hosted CI cycles are required. The PR remains draft.

@adamgell
adamgell requested a review from Copilot August 2, 2026 03:21
@coderabbitai

coderabbitai Bot commented Aug 2, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.


Your included review limit is currently reached under our Fair Usage Limits Policy. This review may still proceed through usage-based billing if eligible. Your next included review will be available in 17 minutes.

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

Copilot reviewed 16 out of 16 changed files in this pull request and generated no new comments.

@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.

🧹 Nitpick comments (1)
crates/cmtraceopen-parser/src/sccm/catalog.rs (1)

632-634: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider moving CCM-record eligibility onto CatalogSpec.

catalog_entry_uses_ccm_records matches on logical_name string literals. A rename of clientMsi or reportingEvents compiles cleanly and silently flips the entry back to true, which routes a non-CCM supplement through raw CCM parsing. A uses_ccm_records: bool field on CatalogSpec keeps the eligibility next to the entry it describes and removes the string coupling.

♻️ Sketch of the field-based alternative
 struct CatalogSpec {
     basename: &'static str,
     logical_name: &'static str,
     role: SccmRole,
     family: SccmArtifactFamily,
+    uses_ccm_records: bool,
 }
-fn catalog_entry_uses_ccm_records(entry: &CatalogSpec) -> bool {
-    !matches!(entry.logical_name, "clientMsi" | "reportingEvents")
-}
+fn catalog_entry_uses_ccm_records(entry: &CatalogSpec) -> bool {
+    entry.uses_ccm_records
+}
🤖 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/sccm/catalog.rs` around lines 632 - 634, Move
CCM-record eligibility onto CatalogSpec by adding a uses_ccm_records boolean
field to each catalog entry and updating catalog_entry_uses_ccm_records to
return that field. Initialize the field explicitly for clientMsi and
reportingEvents as false and for other applicable entries as true, then remove
the logical_name string matching.
🤖 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.

Nitpick comments:
In `@crates/cmtraceopen-parser/src/sccm/catalog.rs`:
- Around line 632-634: Move CCM-record eligibility onto CatalogSpec by adding a
uses_ccm_records boolean field to each catalog entry and updating
catalog_entry_uses_ccm_records to return that field. Initialize the field
explicitly for clientMsi and reportingEvents as false and for other applicable
entries as true, then remove the logical_name string matching.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 2c46eb38-7edf-4449-9811-64226cd3826a

📥 Commits

Reviewing files that changed from the base of the PR and between 34c3aba and 269e713.

📒 Files selected for processing (16)
  • crates/cmtraceopen-parser/src/sccm/catalog.rs
  • crates/cmtraceopen-parser/src/sccm/client/intake.rs
  • crates/cmtraceopen-parser/src/sccm/client/mod.rs
  • crates/cmtraceopen-parser/src/sccm/findings.rs
  • crates/cmtraceopen-parser/src/sccm/mod.rs
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/README.md
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/intake/access-denied/expected.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/intake/capped/expected.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/intake/collision/expected.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/intake/complete/expected.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/intake/missing-root/expected.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/intake/rotations/expected.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/intake/rotations/manifest.json
  • crates/cmtraceopen-parser/tests/sccm_client_intake.rs
  • crates/cmtraceopen-parser/tests/sccm_spine_contract.rs
  • docs/sccm/preparation/issue-319-client-intake.md

@adamgell
adamgell marked this pull request as ready for review August 2, 2026 03:36
@adamgell
adamgell merged commit d1bb525 into codex/parser-family-skeleton Aug 2, 2026
11 checks passed
adamgell added a commit that referenced this pull request Aug 4, 2026
* test(sccm): define pure client intake contract

* feat(sccm): define pure client intake coverage

* test(sccm): harden client intake provenance boundaries

* feat(sccm): validate client intake provenance

* test(sccm): reject unsafe client intake provenance

RED: cargo test --locked -p cmtraceopen-parser --test sccm_client_intake -- --nocapture ran 13 tests: 11 passed and 2 intended privacy regressions failed.

* fix(sccm): bound client intake provenance paths

* test(sccm): pin bounded intake path namespaces

REVIEW RED: focused client intake ran 13 tests: 12 passed and the identity-slot bypass regression failed.

* fix(sccm): allowlist client intake path namespaces

* test(sccm): reject impossible intake timestamp paths

CODERABBIT RED: focused client intake ran 13 tests: 12 passed and the impossible timestamp regression failed.

* fix(sccm): validate intake timestamp path values

* test(sccm): reject unnamespaced path fingerprints

* fix(sccm): namespace client path fingerprints

* test(sccm): reject identity-bearing synthetic handles

* fix(sccm): bound synthetic fingerprint vocabulary

* test(sccm): reject numeric synthetic identities

* fix(sccm): constrain synthetic numeric markers

* test(sccm): reject free-form intake metadata

* fix(sccm): bound intake metadata vocabularies

* test(sccm): reject free-form unknown rotations

* fix(sccm): require opaque unknown rotations

* test(sccm): close intake identity channels

* fix(sccm): bind client intake identities

* test(sccm): preserve shared location rotations

* fix(sccm): bind shared location rotations

* test(sccm): tighten client intake review regressions

* fix(sccm): tighten client path fingerprint grammar

* test(sccm): reject complete capped client fragments

* fix(sccm): fail closed on complete capped fragments

* test(sccm): expose escaped client path probe gap

* test(sccm): harden client intake privacy probes

* test(sccm): expose client intake coverage contradictions

The client intake contract accepts three contradictions. A
Captured fragment admitting fragmentComplete=false passes while
the Capped mirror is rejected. A mixed group with one captured
fragment and one Absent sibling marker reports group coverage
Absent with a gap claiming no artifact was supplied, while the
same group still serializes the captured fragment, because
coverage_rank lets marker states outrank Captured and no test
pins mixed-state groups. Two Absent markers for the same source
under distinct caller labels are both accepted and project as
two fragments because canonical-identity dedup only covers
physical states.

Add failing tests pinning the intended semantics: Captured plus
incomplete fails closed via InvalidFragmentCompleteness, mixed
groups keep the physical coverage and emit per-source gaps that
name the absent or denied source, a capped mix keeps both the
group gap and the per-source gap, and duplicate non-physical
marker identities fail closed via DuplicateArtifactId.

Refs #319

* fix(sccm): keep mixed-group client captures coherent

Before this change the client intake accepted a Captured
fragment that admitted fragmentComplete=false, let coverage_rank
place Absent above Captured so a mixed group diagnosed itself as
unsupplied while serializing the captured fragment, and let two
non-physical markers double-declare the same source under
distinct caller labels.

Reject Captured plus incomplete via InvalidFragmentCompleteness,
mirroring the Capped plus complete rule, since Capped exists to
represent an incomplete capture. Compute group coverage from the
physical fragments whenever any exist and emit an explicit
per-source gap for each sibling marker that names the affected
source, so absence stays a diagnosis without erasing captured
evidence. Extend canonical-identity dedup to non-physical
markers keyed on basename, rotation, and optional path
fingerprint, mirroring the duplicate-identity idiom the server
lane uses for physical states; markers distinguished by explicit
fingerprints remain distinct sources.

Also document that physicalArtifacts intentionally includes
non-physical markers and that markers may carry a path
fingerprint, both flagged by review as worth stating as
intended.

Refs #319

* test(sccm): probe forward-slash user-root leak detection

The serialized privacy probe only matches the JSON-escaped
backslash form c:\\users, so a forward-slash normalized leak
such as c:/users/... with the RealUser sentinel stripped passes
every serialized privacy assertion undetected.

Add a failing meta-test that feeds the probe a forward-slash
normalized Windows user path and requires detection, per the
non-blocking hardening in the exact-head review.

Refs #319

* fix(sccm): match normalized user roots in privacy probe

The probe helper only recognized the JSON-escaped c:\\users
form, leaving forward-slash normalized Windows user paths
invisible to every serialized privacy assertion when the
RealUser sentinel is absent.

Also match the normalized c:/users form so either separator
style trips the probe, closing the review's non-blocking
hardening gap.

Refs #319

* test(sccm): expose marker collisions with physical sources

A fingerprint-less absent marker for a source that is also
physically declared is accepted, and the assessment then claims
no artifact for the source was supplied while serializing the
captured fragment, the exact self-contradiction class round 6
blocked on. The same root lets an unpinned marker and a
fingerprint-pinned marker double-declare one source, and lets a
pinned marker contradict physical evidence for its own source.

Add failing tests requiring the canonical source identity,
basename plus rotation, to intersect across all declarations:
a non-physical marker never shares basename and rotation with a
physical declaration regardless of fingerprints, an unpinned
marker collides with any other declaration for its source, and
both directions hold for either declaration order. Pin the
accepted direction, a marker for a genuinely distinct rotation
alongside the capture, and pin the intentionally two-valued
ParseFailed fragment completeness the review listed as the last
unpinned matrix cell. Document the client/server fingerprint
asymmetry as a follow-up.

Refs #319

* fix(sccm): intersect source identity across declarations

The marker identity set keyed on basename, rotation, and the
optional path fingerprint never intersected physical
declarations, so a fingerprint-less absent marker for a captured
source was accepted and the assessment asserted a coverage gap
its own fragments array disproved. The same root let an unpinned
marker and a fingerprint-pinned marker double-declare one
source, and let a pinned marker contradict physical evidence for
its own source whenever the fingerprints differed.

Track the canonical source identity, casefolded basename plus
rotation discriminator, for every declaration and intersect it
across all declaration shapes. A non-physical marker sharing its
source identity with a physical declaration fails closed with
CollidingPhysicalIdentity in either declaration order,
regardless of fingerprints, because physical evidence disproves
any absent, denied, or skipped claim about the same source. A
fingerprint-less marker collides with any other declaration for
its source via DuplicateArtifactId, while markers pinned to
distinct roots by distinct fingerprints stay distinct sources
when no physical declaration exists. Physical declarations keep
their existing fingerprint and relative-path dedup, so distinct
captured rotations and root collisions stay representable.

The sibling server intake closes this class by making the path
fingerprint mandatory everywhere; the client keeps optional
marker fingerprints for the committed all-absent fixtures, with
convergence documented as a follow-up in the intake tests.

Refs #319

* test(sccm): pin exact client intake error variants

Ten assertions checked only is_err(). SccmClientIntakeError has 14
variants, so each passed when any validator rejected the bundle,
including for a reason unrelated to the behavior under test. Each
now compares against the exact expected variant.

Pinning exposed two inputs that rejected for the wrong reason:

malformed_rotation_and_public_provenance_values_fail_closed declared
SccmRotation::Timestamped("2026-bad") to exercise the rotation
grammar, but synthetic_artifact derived an "unknown" group segment
from the rotated basename. The bundle failed on InvalidRelativePath
before reaching the rotation check, so the rotation contract was
never exercised. The artifact now carries a consistent relative path
and the malformed timestamp is the only contract it violates. The
rotation grammar itself lives in the SccmRotation Serialize impl,
which validate_bundle reaches through serde_json::to_value.

fragment_completeness_and_every_path_fingerprint_are_explicit_and_
unambiguous asserted that an AccessDenied marker with no relative
path fails its provenance contract. AccessDenied is not a physical
state, so MissingPhysicalProvenance is unreachable for that input;
the marker actually fails on InvalidFragmentCompleteness because it
retains the default fragmentComplete=true. The assertion now pins
that variant, and a new physical case with its relative path
stripped covers MissingPhysicalProvenance directly.

Refs #319

* refactor(sccm): own the sha256 digest width in one helper

is_lowercase_hex_handle served both 16-character root handles and
64-character SHA-256 digests, so every digest caller had to restate
its own length guard. Four call sites repeated it, and a new caller
that omitted it would silently accept a 16-character handle.

is_sha256_digest now owns the digest width and the four digest
callers use it. is_lowercase_hex_handle keeps its 16-or-64 root
grammar unchanged; narrowing the root contract would be a behavior
change, not a refactor. Both delegate to a shared is_lowercase_hex.

Refs #319

* test(sccm): casefold every serialized leak assertion

unsupported_physical_artifacts_retain_safe_provenance_without_raw_
host_or_path compared against the original-case serialized JSON, so
a projection that normalized case would leak RealUser or
real-user-host and still pass. It also used bare substring checks,
which miss the JSON-escaped and forward-slash normalized Windows
user roots that carry no sentinel.

Swept every serialized-leak assertion in the file. Two sites exist.
The first already casefolded and routed through
serialized_json_contains_windows_user_root; this commit brings the
second to the same shape. Positive assertions keep their exact case
on purpose, with a comment saying why, because they pin what the
projection must reproduce verbatim.

This class has now surfaced twice, so the contract is enforced
rather than documented: the helper carries a doc comment stating the
rule and a debug_assert that rejects a caller passing original-case
input. Verified the guard fires by temporarily feeding it the
uncased string.

Siblings were checked and are not this class.
sccm_client_intake_fixture_contract asserts a fixture lacks a [cut]
marker, and sccm_spine_contract asserts redaction of parsed message
strings, a surface that must retain C:\Windows\CCM\Logs verbatim.

Refs #319

* fix(sccm): preserve partial client intake coverage

* fix(sccm): repair client intake contracts (#432)

* fix(sccm): repair client intake contracts (#319)

* fix(sccm): bind multi-dot catalog requests (#319)

* fix(sccm): bind and order client source lineages (#319)

* fix(sccm): align client setup catalog identity (#319)

* test(sccm): construct invalid requests without serialization

* test(sccm): expose client intake wire gaps

* fix(sccm): validate client intake wire projections

* docs(sccm): align client intake delivery state

* test(sccm): expose incomplete client intake oracle

* test(sccm): bind complete client intake fixture oracle

* docs(sccm): enumerate client coverage states

* test(sccm): separate parse failure from fragment bounds

* fix(sccm): distinguish parse failure from fragment bounds

* docs(sccm): close client intake review nits

* docs(sccm): clarify client intake fixture contracts

* fix(sccm): stabilize client intake wire shape
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request feature New feature parser Log parser related sccm SCCM/ConfigMgr related test Testing related

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants