Implements provider access hardening for Intune write operations: - RBAC-based write gate with configurable staleness thresholds - Gate enforced at restore start and in jobs (execute + assignments) - UI affordances: disabled rerun action, tenant RBAC status card, refresh RBAC action - Audit logging for blocked writes - Ops UX label: `rbac.health_check` now displays as “RBAC health check” - Adds/updates Pest tests and SpecKit artifacts for feature 108 Notes: - Filament v5 / Livewire v4 compliant. - Destructive actions require confirmation. - Assets: no new global assets. Tested: - `vendor/bin/sail artisan test --compact` (suite previously green) + focused OpsUx tests for OperationCatalog labels. - `vendor/bin/sail bin pint --dirty`. Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #132
68 lines
3.4 KiB
Markdown
68 lines
3.4 KiB
Markdown
# Research — Provider Access Hardening v1 (Intune Write Gate)
|
|
|
|
## Repository Reality Check (existing implementation surfaces)
|
|
|
|
### Write start surfaces
|
|
|
|
- Restore execution start (wizard submit / create path): `App\Filament\Resources\RestoreRunResource::createRestoreRun()`
|
|
- Creates a queued `RestoreRun` and a corresponding `OperationRun` of type `restore.execute`.
|
|
- Dispatches `App\Jobs\ExecuteRestoreRunJob` with the `OperationRun` instance.
|
|
- Restore rerun path (action path inside `RestoreRunResource`): also enqueues `restore.execute` and dispatches `ExecuteRestoreRunJob`.
|
|
|
|
### Job execution layer (defense-in-depth insertion points)
|
|
|
|
- `App\Jobs\ExecuteRestoreRunJob::handle()`
|
|
- Calls `RestoreService::executeForRun(...)` (this is the Graph-mutation path).
|
|
- `App\Jobs\RestoreAssignmentsJob::handle()`
|
|
- Calls `AssignmentRestoreService::restore(...)` (Graph-mutation path for assignments).
|
|
|
|
### Tenant view RBAC UX surfaces
|
|
|
|
- Tenant view page: `App\Filament\Resources\TenantResource::infolist()` currently renders a full "RBAC" section with many raw fields.
|
|
- Tenant view header actions: `App\Filament\Resources\TenantResource\Pages\ViewTenant::getHeaderActions()` includes `TenantResource::rbacAction()`.
|
|
- RBAC setup surface already exists: `App\Filament\Resources\TenantResource::rbacAction()` creates the "Setup Intune RBAC" action (no new wizard page required).
|
|
|
|
### Existing gating and observability primitives
|
|
|
|
- Operation dedupe + provider connection blocking: `App\Services\Providers\ProviderOperationStartGate` (existing pattern for start surfaces).
|
|
- Long-running work visibility: `OperationRun` is the canonical monitoring primitive.
|
|
- Audit logging: `App\Models\AuditLog` exists and `Tenant` already relates to it.
|
|
|
|
## Decisions (resolved clarifications)
|
|
|
|
### Gate evaluation during health check
|
|
|
|
- Decision: Gate evaluates persisted Tenant state only; an in-progress health check has no special effect.
|
|
- Rationale: Keeps the gate DB-only and deterministic; avoids introducing locks/sentinels.
|
|
- Alternatives considered:
|
|
- Block all writes while health check is running (safer but adds operational friction and requires tracking “running” state).
|
|
|
|
### "Setup Intune RBAC" CTA destination
|
|
|
|
- Decision: CTA deep-links to the existing Tenant view RBAC section / surfaces (no new wizard page in this feature).
|
|
- Rationale: Minimizes scope and leverages `TenantResource::rbacAction()` which already exists.
|
|
- Alternatives considered:
|
|
- Build a dedicated setup wizard page for RBAC (adds navigation, testing, and more UX requirements).
|
|
|
|
### Audit logging for blocked attempts
|
|
|
|
- Decision: Use existing `AuditLog` model for UI-level blocked write attempts (P3), in addition to OperationRun failures.
|
|
- Rationale: Meets compliance intent without introducing new schema.
|
|
- Alternatives considered:
|
|
- Create a new audit log table (unnecessary; model already exists).
|
|
|
|
### Config toggle behavior
|
|
|
|
- Decision: `tenantpilot.hardening.intune_write_gate.enabled=false` causes writes to proceed, but logs a warning per evaluation that the gate is bypassed.
|
|
- Rationale: Rollback safety without silent loss of protection.
|
|
- Alternatives considered:
|
|
- Silent bypass (bad observability).
|
|
- Startup-only warning (can be missed; per-evaluation warning is explicit).
|
|
|
|
## Key constraints reaffirmed
|
|
|
|
- No synchronous Graph calls in the gate.
|
|
- Start surface must block before job enqueue.
|
|
- Job-level must block before any Graph mutation call.
|
|
- Reason codes are stable and sanitized.
|