## Summary - add Intune RBAC Role Definition baseline scope support, capture references, compare classification, findings evidence, and landing/detail UI labels - keep Intune Role Assignments explicitly excluded from baseline compare scope, summaries, findings, and restore messaging - add focused Pest coverage for baseline scope selection, capture, compare behavior, recurrence, isolation, findings rendering, inventory anchoring, and RBAC summaries ## Verification - `vendor/bin/sail bin pint --dirty --format agent` - `vendor/bin/sail artisan test --compact tests/Unit/Inventory/InventoryPolicyTypeMetaBaselineSupportTest.php tests/Unit/Baselines/BaselinePolicyVersionResolverTest.php tests/Unit/Baselines/BaselineScopeTest.php tests/Unit/IntuneRoleDefinitionNormalizerTest.php tests/Feature/Baselines/BaselineCaptureRbacRoleDefinitionsTest.php tests/Feature/Baselines/BaselineCompareRbacRoleDefinitionsTest.php tests/Feature/Baselines/BaselineCompareDriftEvidenceContractRbacTest.php tests/Feature/Baselines/BaselineCompareCoverageGuardTest.php tests/Feature/Baselines/BaselineCompareCrossTenantMatchTest.php tests/Feature/Baselines/BaselineCompareFindingRecurrenceKeyTest.php tests/Feature/Baselines/BaselineCompareWhyNoFindingsReasonCodeTest.php tests/Feature/Filament/BaselineProfileFoundationScopeTest.php tests/Feature/Filament/BaselineSnapshotRbacRoleDefinitionsTest.php tests/Feature/Filament/BaselineCompareLandingRbacLabelsTest.php tests/Feature/Filament/FindingViewRbacEvidenceTest.php tests/Feature/Findings/FindingRecurrenceTest.php tests/Feature/Findings/DriftStaleAutoResolveTest.php tests/Feature/Inventory/InventorySyncButtonTest.php tests/Feature/Inventory/InventorySyncServiceTest.php tests/Feature/RunAuthorizationTenantIsolationTest.php` - result: `71 passed (467 assertions)` ## Filament / Platform Notes - Livewire compliance: unchanged and compatible with Livewire v4.0+ - Provider registration: no panel/provider changes; `bootstrap/providers.php` remains the registration location - Global search: no new globally searchable resource added; existing global search behavior is unchanged - Destructive actions: no new destructive actions introduced; existing confirmed actions remain unchanged - Assets: no new Filament assets introduced; deploy asset handling remains unchanged, including `php artisan filament:assets` - Testing plan covered: baseline profile scope, snapshot detail, compare job, findings recurrence, findings detail, compare landing labels, inventory sync anchoring, and tenant isolation Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #156
253 lines
16 KiB
Markdown
253 lines
16 KiB
Markdown
# Implementation Plan: Intune RBAC Baseline Compare & Findings v1
|
||
|
||
**Branch**: `feat/128-rbac-baseline-compare` | **Date**: 2026-03-09 | **Spec**: `specs/128-rbac-baseline-compare/spec.md`
|
||
**Input**: Feature specification from `specs/128-rbac-baseline-compare/spec.md`
|
||
|
||
## Summary
|
||
|
||
Extend the existing baseline capture and compare engine to support one additional foundation type, `intuneRoleDefinition`, by introducing explicit baseline-support metadata, capturing Role Definition baseline references from the existing RBAC version history, and adding an ID-based normalized compare path that emits unified baseline.compare findings with RBAC-specific severity, evidence, and summaries. Keep `intuneRoleAssignment` explicitly excluded from baseline scope, compare, and findings.
|
||
|
||
## Technical Context
|
||
|
||
**Language/Version**: PHP 8.4
|
||
**Primary Dependencies**: Laravel 12, Filament v5, Livewire v4
|
||
**Storage**: PostgreSQL via Laravel Sail
|
||
**Testing**: Pest v4 on PHPUnit 12
|
||
**Target Platform**: Dockerized Laravel web application (Sail)
|
||
**Project Type**: Web application
|
||
**Performance Goals**: Baseline capture and compare stay chunked and DB-first, avoid UI-time Graph calls, and remain bounded by covered in-scope subjects
|
||
**Constraints**: Existing Ops-UX `OperationRun` contract, numeric-only `summary_counts`, deny-as-not-found tenant/workspace isolation, no RBAC write path, and deterministic compare/finding identity
|
||
**Scale/Scope**: Workspace-owned baseline profiles and snapshots plus tenant-scoped compare runs and findings across potentially large in-scope baseline subject sets
|
||
|
||
## Constitution Check
|
||
|
||
*GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.*
|
||
|
||
- Inventory-first: PASS — current state remains `InventoryItem` plus existing RBAC `PolicyVersion` evidence from Spec 127; baseline snapshots stay immutable.
|
||
- Read/write separation: PASS — this release is read-only governance analysis; no restore or Graph write behavior is added.
|
||
- Graph contract path: PASS — existing `intuneRoleDefinition` and `intuneRoleAssignment` contracts already exist in `config/graph_contracts.php`; compare and UI rendering remain DB-only at runtime.
|
||
- Deterministic capabilities: PASS — scope eligibility can be derived from config metadata and helper filters with tests; no raw capability strings are needed.
|
||
- RBAC-UX planes and isolation: PASS — workspace baseline management stays in the tenant/admin plane, compare and findings stay tenant-context, and cross-plane behavior is unchanged.
|
||
- Workspace isolation: PASS — baseline profiles and snapshots remain workspace-owned; workspace membership enforcement remains unchanged.
|
||
- Tenant isolation: PASS — compare runs, current inventory, and findings remain tenant-owned and deny-as-not-found for non-members.
|
||
- Destructive confirmation: PASS — no new destructive RBAC action is introduced; existing baseline archive/capture surfaces keep their current confirmation semantics.
|
||
- Global search: PASS — no new searchable resource is added, so the existing global-search rules are unaffected.
|
||
- Run observability: PASS — baseline capture and compare already use `OperationRun` and queued jobs; this release only extends their scope and result payloads.
|
||
- Ops-UX 3-surface feedback: PASS — baseline start surfaces already use queued-only toasts and canonical run links.
|
||
- Ops-UX lifecycle: PASS — `OperationRun` transitions remain service-owned through `OperationRunService`.
|
||
- Ops-UX summary counts: PASS — RBAC-specific counts can live in `context.baseline_compare` while `summary_counts` stay numeric-only.
|
||
- Ops-UX guards: PASS — existing baseline compare guard tests can be extended for the new foundation type.
|
||
- Ops-UX system runs: PASS — unchanged; initiator-null behavior remains handled by the existing operation framework.
|
||
- Data minimization: PASS — inventory remains metadata-only; baseline evidence reuses existing version references and normalized snapshots without introducing secret-bearing payloads.
|
||
- Badge semantics: PASS — severity and label additions can use the centralized badge and renderer system.
|
||
- Filament Action Surface Contract: PASS — only existing Baseline Profile, Baseline Snapshot, Baseline Compare, and Findings surfaces are extended; no new resource or unreviewed action surface is introduced.
|
||
- Filament UX-001: PASS — the feature only adjusts scope options, summaries, and evidence blocks inside established sectioned forms and detail screens.
|
||
- Filament v5 / Livewire v4 compliance: PASS — no version or API changes are introduced.
|
||
- Provider registration (`bootstrap/providers.php`): PASS — no new providers or panels are introduced.
|
||
- Global search resource rule: PASS — no new globally searchable resource is added.
|
||
- Asset strategy: PASS — no new panel or shared assets are needed; `filament:assets` deployment behavior is unchanged.
|
||
|
||
## Project Structure
|
||
|
||
### Documentation (this feature)
|
||
|
||
```text
|
||
specs/128-rbac-baseline-compare/
|
||
├── plan.md
|
||
├── research.md
|
||
├── data-model.md
|
||
├── quickstart.md
|
||
├── contracts/
|
||
│ └── openapi.yaml
|
||
├── checklists/
|
||
│ └── requirements.md
|
||
└── tasks.md
|
||
```
|
||
|
||
### Source Code (repository root)
|
||
|
||
```text
|
||
app/
|
||
├── Filament/
|
||
│ ├── Pages/
|
||
│ │ └── BaselineCompareLanding.php
|
||
│ └── Resources/
|
||
│ ├── BaselineProfileResource.php
|
||
│ └── BaselineSnapshotResource.php
|
||
├── Jobs/
|
||
│ ├── CaptureBaselineSnapshotJob.php
|
||
│ └── CompareBaselineToTenantJob.php
|
||
├── Models/
|
||
│ ├── BaselineProfile.php
|
||
│ ├── BaselineSnapshot.php
|
||
│ ├── BaselineSnapshotItem.php
|
||
│ ├── Finding.php
|
||
│ ├── InventoryItem.php
|
||
│ └── PolicyVersion.php
|
||
├── Services/
|
||
│ ├── Baselines/
|
||
│ │ ├── BaselineCaptureService.php
|
||
│ │ ├── BaselineCompareService.php
|
||
│ │ ├── BaselineAutoCloseService.php
|
||
│ │ ├── BaselineSnapshotIdentity.php
|
||
│ │ └── Evidence/
|
||
│ ├── Intune/
|
||
│ │ ├── IntuneRoleDefinitionNormalizer.php
|
||
│ │ └── PolicyNormalizer.php
|
||
│ └── Inventory/
|
||
│ └── InventorySyncService.php
|
||
├── Support/
|
||
│ ├── Baselines/
|
||
│ │ ├── BaselineCompareReasonCode.php
|
||
│ │ ├── BaselineScope.php
|
||
│ │ └── BaselineSubjectKey.php
|
||
│ ├── Badges/
|
||
│ └── Inventory/
|
||
│ └── InventoryPolicyTypeMeta.php
|
||
config/
|
||
├── graph_contracts.php
|
||
└── tenantpilot.php
|
||
tests/
|
||
├── Feature/
|
||
│ ├── Baselines/
|
||
│ ├── Findings/
|
||
│ ├── Filament/
|
||
│ └── Inventory/
|
||
└── Unit/
|
||
└── IntuneRoleDefinitionNormalizerTest.php
|
||
```
|
||
|
||
**Structure Decision**: Keep all work in the existing Laravel application. The feature is a targeted extension of current baseline capture/compare services, baseline Filament surfaces, config-driven type metadata, and existing baseline/findings tests.
|
||
|
||
## Complexity Tracking
|
||
|
||
No constitution violations are required for this feature.
|
||
|
||
## Phase 0 — Outline & Research (DONE)
|
||
|
||
Outputs:
|
||
- `specs/128-rbac-baseline-compare/research.md`
|
||
|
||
Key findings captured:
|
||
- Baseline scope already supports `foundation_types`, but the current UI options list every configured foundation type without an explicit baseline-support gate.
|
||
- Baseline capture already queries `scope->allTypes()` and can include foundations, but current subject identity is display-name-derived via `BaselineSubjectKey`, which is not acceptable for Role Definition compare.
|
||
- Compare and finding upsert infrastructure already supports unified lifecycle, evidence provenance, coverage guards, and recurrence logic; this feature should plug into those seams rather than inventing a separate RBAC compare engine.
|
||
|
||
## Phase 1 — Design & Contracts (DONE)
|
||
|
||
Outputs:
|
||
- `specs/128-rbac-baseline-compare/data-model.md`
|
||
- `specs/128-rbac-baseline-compare/contracts/openapi.yaml`
|
||
- `specs/128-rbac-baseline-compare/quickstart.md`
|
||
|
||
Design highlights:
|
||
- Add explicit baseline-compare metadata on foundation types so `intuneRoleDefinition` is opt-in supported and `intuneRoleAssignment` remains explicitly unsupported.
|
||
- Extend baseline capture and compare with a Role Definition ID identity strategy while leaving the existing display-name subject-key flow in place for previously supported policy types.
|
||
- Reuse `IntuneRoleDefinitionNormalizer::flattenForDiff()` for normalized governance diffs and feed the result into the existing baseline evidence and finding contracts.
|
||
|
||
## Phase 1 — Agent Context Update (DONE)
|
||
|
||
Run:
|
||
- `.specify/scripts/bash/update-agent-context.sh copilot`
|
||
|
||
## Phase 2 — Implementation Plan
|
||
|
||
### Step 1 — Add explicit baseline-support metadata for foundation types
|
||
|
||
Goal: implement FR-128-01 through FR-128-04.
|
||
|
||
Changes:
|
||
- Extend `config/tenantpilot.php` foundation-type rows with explicit baseline-compare support metadata instead of implicitly treating every foundation as baseline-eligible.
|
||
- Mark `intuneRoleDefinition` as supported for baseline compare and `intuneRoleAssignment` as unsupported.
|
||
- Add helper accessors in `App\Support\Inventory\InventoryPolicyTypeMeta` for baseline-supported foundations so scope selection, summaries, and tests read from one canonical source.
|
||
- Update `BaselineProfileResource::foundationTypeOptions()` and related infolist formatting to show only eligible foundation types while making the RBAC Role Definition label explicit.
|
||
|
||
Tests:
|
||
- Add or update focused tests proving `intuneRoleDefinition` is baseline-supported and `intuneRoleAssignment` is excluded.
|
||
- Add or update baseline profile selection tests proving Role Definitions can be chosen and Assignments cannot leak into the saved scope.
|
||
|
||
### Step 2 — Introduce Role Definition ID identity for baseline capture and compare
|
||
|
||
Goal: implement FR-128-05 through FR-128-10.
|
||
|
||
Changes:
|
||
- Extend the baseline subject identity model so `intuneRoleDefinition` can use stable external ID matching instead of the current display-name-derived `BaselineSubjectKey` flow.
|
||
- Update `CaptureBaselineSnapshotJob::collectInventorySubjects()` and `buildSnapshotItems()` to preserve the tenant Role Definition ID, a workspace-safe external reference, and an explicit identity marker for Role Definition baseline items.
|
||
- Update compare-side loaders in `CompareBaselineToTenantJob` so Role Definitions are loaded and matched by Role Definition ID while existing policy types keep their current behavior.
|
||
- Ensure delete-and-recreate with a new ID resolves to `missing` + `unexpected`, not a silent rename match.
|
||
|
||
Tests:
|
||
- Add capture tests proving baseline snapshot items for `intuneRoleDefinition` keep evidence-ready references and exclude `intuneRoleAssignment`.
|
||
- Add compare tests proving same-name/different-ID Role Definitions do not match and instead produce missing/unexpected outcomes.
|
||
|
||
### Step 3 — Add normalized RBAC Role Definition diffing and classification
|
||
|
||
Goal: implement FR-128-11 through FR-128-19.
|
||
|
||
Changes:
|
||
- Introduce a narrow Role Definition compare helper that uses `IntuneRoleDefinitionNormalizer::flattenForDiff()` as the governance-normalized diff surface.
|
||
- Define classification logic for unchanged, modified, missing, and unexpected Role Definitions.
|
||
- Split modified Role Definition diffs into metadata-only versus permission-impacting changes so severity can map to Low versus High.
|
||
- Reuse existing coverage-guard and evidence-gap handling so provider or permission issues suppress false findings instead of inventing RBAC-only failure semantics.
|
||
|
||
Tests:
|
||
- Add normalized diff tests that prove ordering noise in permission blocks is ignored.
|
||
- Add compare classification tests for unchanged, modified, missing, and unexpected Role Definitions.
|
||
- Add severity tests proving permission changes are High, missing is High, unexpected is Medium, and metadata-only is Low.
|
||
|
||
### Step 4 — Extend finding evidence, fingerprints, and run summaries for RBAC
|
||
|
||
Goal: implement FR-128-18 through FR-128-26.
|
||
|
||
Changes:
|
||
- Implement the `intuneRoleDefinition` finding fingerprint composition explicitly in the compare job so the stable fingerprint includes baseline profile scope, Role Definition identity, change kind, and normalized diff fingerprint inputs.
|
||
- Reuse baseline compare finding upsert and recurrence behavior, keeping fingerprints recurrence-stable and profile-scoped while adding `intuneRoleDefinition`-specific diff fingerprints as evidence inputs.
|
||
- Extend the evidence contract builder to emit an RBAC-specific `summary.kind`, readable before/after normalized evidence, baseline and current version references, and built-in/custom visibility.
|
||
- Extend compare-run context with an RBAC Role Definition summary bucket: total compared, unchanged, modified, missing, and unexpected.
|
||
- Update label and presentation helpers so findings and run detail surfaces identify these records as Intune RBAC Role Definition drift, not generic policy drift.
|
||
|
||
Tests:
|
||
- Add or update evidence contract tests for modified, missing, and unexpected RBAC Role Definition findings.
|
||
- Add fingerprint/idempotency tests for repeated identical compare runs and recurrence tests for resolved-then-reappearing RBAC drift.
|
||
- Add summary serialization tests for the RBAC run-level counts.
|
||
|
||
### Step 5 — Extend existing Filament surfaces without introducing RBAC restore semantics
|
||
|
||
Goal: implement FR-128-24 through FR-128-29 and the UX-001 layout and UI Action Matrix constraints already defined in the spec and constitution.
|
||
|
||
Changes:
|
||
- Update existing baseline profile, baseline snapshot, compare landing or run detail, and findings detail surfaces to surface Role Definition scope, summary counts, RBAC-specific wording, and readable evidence blocks.
|
||
- Keep action surfaces unchanged except for the new scope option and evidence presentation; no new destructive or restore actions are introduced.
|
||
- Use existing badge and tag renderers for any new severity or compare-state display values.
|
||
- Ensure no screen text implies Role Assignment coverage or executable RBAC restore.
|
||
|
||
Tests:
|
||
- Add or update Filament tests asserting the baseline profile scope picker shows Intune Role Definition and not Intune Role Assignment.
|
||
- Add or update UI tests for compare landing and finding detail labels so RBAC findings are clearly labeled, show readable evidence, and do not imply restore support.
|
||
|
||
### Step 6 — Preserve safe degradation, auditability, and isolation semantics
|
||
|
||
Goal: implement FR-128-28 through FR-128-30 and the failure-path test requirements.
|
||
|
||
Changes:
|
||
- Reuse compare coverage and evidence-gap reason codes for RBAC so unavailable current-state data results in warning or partial-success outcomes instead of false drift.
|
||
- Ensure RBAC compare audit events and `OperationRun.context` capture effective scope, RBAC compare counts, and suppression reasons without adding non-canonical `summary_counts` keys.
|
||
- Confirm workspace and tenant scoping on compare queries, finding upserts, and UI read paths.
|
||
|
||
Tests:
|
||
- Add isolation coverage ensuring one tenant’s Role Definition baseline items and findings cannot match another tenant’s current state.
|
||
- Add failure-path tests proving provider or permission gaps emit zero false RBAC findings.
|
||
- Keep existing baseline compare coverage-guard, run-authorization, and stale auto-close tests passing.
|
||
|
||
## Post-design Constitution Re-check
|
||
|
||
Expected: PASS.
|
||
|
||
- Livewire v4.0+ compliance: unchanged and preserved because no new Filament panel or Livewire version changes are introduced.
|
||
- Provider registration location: unchanged; no new providers or panel registration changes outside `bootstrap/providers.php`.
|
||
- Globally searchable resources: unchanged; no new Resource is added, so no new Edit/View global-search requirement applies.
|
||
- Destructive actions: unchanged; existing baseline archive actions remain confirmed and no new destructive RBAC action is added.
|
||
- Asset strategy: unchanged; no new assets are introduced, so the existing deploy-time `php artisan filament:assets` behavior remains sufficient.
|
||
- Testing plan: extend focused Pest coverage for baseline eligibility, scope selection, capture references, compare classification, evidence, severity, fingerprinting, assignment exclusion, isolation, failure paths, and unchanged baseline behavior for existing supported types.
|
||
|