From 662b0e0aa8ec4268a73633fb527bdf10e1d7be71 Mon Sep 17 00:00:00 2001 From: Ahmed Darrazi Date: Sun, 4 Jan 2026 00:18:34 +0100 Subject: [PATCH] spec: refresh specs/plans + add 018 scaffolding --- .specify/memory/constitution.md | 63 +++---- .specify/plan.md | 26 +-- .specify/spec.md | 155 ++++++++++++++++-- .specify/tasks.md | 16 +- .../checklists/requirements.md | 15 ++ specs/018-driver-updates-wufb/plan.md | 24 +++ specs/018-driver-updates-wufb/spec.md | 77 +++++++++ specs/018-driver-updates-wufb/tasks.md | 32 ++++ .../checklists/requirements.md | 17 +- specs/023-endpoint-security-restore/plan.md | 3 +- specs/023-endpoint-security-restore/spec.md | 4 +- specs/023-endpoint-security-restore/tasks.md | 35 ++-- 12 files changed, 368 insertions(+), 99 deletions(-) create mode 100644 specs/018-driver-updates-wufb/checklists/requirements.md create mode 100644 specs/018-driver-updates-wufb/plan.md create mode 100644 specs/018-driver-updates-wufb/spec.md create mode 100644 specs/018-driver-updates-wufb/tasks.md diff --git a/.specify/memory/constitution.md b/.specify/memory/constitution.md index a4670ff..8670192 100644 --- a/.specify/memory/constitution.md +++ b/.specify/memory/constitution.md @@ -1,50 +1,35 @@ -# [PROJECT_NAME] Constitution - +# TenantPilot Constitution ## Core Principles -### [PRINCIPLE_1_NAME] - -[PRINCIPLE_1_DESCRIPTION] - +### Safety-First Restore +- Any destructive action MUST support preview/dry-run, explicit confirmation, and a clear pre-execution summary. +- High-risk policy types default to `preview-only` restore unless explicitly enabled by a feature spec + tests + checklist. +- Restore must be defensive: validate inputs, detect conflicts, allow selective restore, and record outcomes per item. -### [PRINCIPLE_2_NAME] - -[PRINCIPLE_2_DESCRIPTION] - +### Auditability & Tenant Isolation +- Every operation is tenant-scoped and MUST write an audit log entry (no secrets, no tokens). +- Snapshots are immutable JSONB and MUST remain reproducible (who/when/what/source tenant). -### [PRINCIPLE_3_NAME] - -[PRINCIPLE_3_DESCRIPTION] - +### Graph Abstraction & Contracts +- All Microsoft Graph calls MUST go through `GraphClientInterface`. +- Contract assumptions are config-driven (`config/graph_contracts.php`); do not hardcode endpoints in feature code. +- Unknown/missing policy types MUST fail safe (preview-only / no Graph calls) rather than calling `deviceManagement/{type}`. -### [PRINCIPLE_4_NAME] - -[PRINCIPLE_4_DESCRIPTION] - +### Least Privilege +- Prefer least-privilege roles/scopes; surface warnings when higher privileges are selected. +- Never store secrets in code/config; never log credentials or tokens. -### [PRINCIPLE_5_NAME] - -[PRINCIPLE_5_DESCRIPTION] - +### Spec-First Workflow +- For any feature that changes runtime behavior, include or update `specs/-/` with `spec.md`, `plan.md`, `tasks.md`, and `checklists/requirements.md`. +- New work branches from `dev` using `feat/-` (spec + code in the same PR). -## [SECTION_2_NAME] - - -[SECTION_2_CONTENT] - - -## [SECTION_3_NAME] - - -[SECTION_3_CONTENT] - +## Quality Gates +- Changes MUST be programmatically tested (Pest) and run via targeted `php artisan test ...`. +- Run `./vendor/bin/pint --dirty` before finalizing. ## Governance - +- This constitution applies across the repo. Feature specs may add stricter constraints but not weaker ones. +- Restore semantics changes require: spec update, checklist update, and tests proving safety. -[GOVERNANCE_RULES] - - -**Version**: [CONSTITUTION_VERSION] | **Ratified**: [RATIFICATION_DATE] | **Last Amended**: [LAST_AMENDED_DATE] - +**Version**: 1.0.0 | **Ratified**: 2026-01-03 | **Last Amended**: 2026-01-03 diff --git a/.specify/plan.md b/.specify/plan.md index d5d5e5b..eb4bfe3 100644 --- a/.specify/plan.md +++ b/.specify/plan.md @@ -1,16 +1,16 @@ # Implementation Plan: TenantPilot v1 -**Branch**: `tenantpilot-v1` -**Date**: 2025-12-12 -**Spec Source**: `.specify/spec.md` (scope/restore matrix unchanged) +**Branch**: `dev` +**Date**: 2026-01-03 +**Spec Source**: `.specify/spec.md` (scope/restore matrix is config-driven) ## Summary -TenantPilot v1 already delivers tenant-scoped Intune inventory, immutable backups, version history with diffs, defensive restore flows, tenant setup, permissions/health, settings normalization/display, and Highlander enforcement. Remaining priority work is the delegated Intune RBAC onboarding wizard (US7) and afterwards the Graph Contract Registry & Drift Guard (US8). All Graph calls stay behind the abstraction with audit logging; snapshots remain JSONB with safety gates (preview-only for high-risk types). +TenantPilot v1 delivers tenant-scoped Intune inventory, immutable backups, version history with diffs, defensive restore flows, tenant setup, permissions/health, settings normalization/display, Highlander enforcement, the delegated RBAC onboarding wizard (US7), and the Graph Contract Registry & Drift Guard (US8). All Graph calls stay behind the abstraction with audit logging; snapshots remain JSONB with safety gates (preview-only for high-risk types). ## Status Snapshot (tasks.md is source of truth) -- **Done**: US1 inventory, US2 backups, US3 versions/diffs, US4 restore preview/exec, scope config, soft-deletes/housekeeping, Highlander single current tenant, tenant setup & verify (US6), permissions/health overview (US6), table ActionGroup UX, settings normalization/display (US1b), Dokploy/Sail runbooks. -- **Next up**: **US7** Intune RBAC onboarding wizard (delegated, synchronous Filament flow). -- **Upcoming**: **US8** Graph Contract Registry & Drift Guard (contract registry, type-family handling, verification command, fallback strategies). +- **Done**: Phases 1–15 (US1–US8, Settings Catalog hydration/display, restore rerun, Highlander, permissions/health, housekeeping/UX, ops). +- **Open**: T167 (optional) CLI/Job for CHECK/REPORT only (no grant). +- **Next up**: Feature 018 (Driver Updates / WUfB add-on) in `specs/018-driver-updates-wufb/`. ## Technical Baseline - Laravel 12, Filament 4, PHP 8.4; Sail-first with PostgreSQL. @@ -28,10 +28,12 @@ ## Completed Workstreams (no new action needed) - **US6 Tenant Setup & Highlander (Phases 8 & 12)**: Tenant CRUD/verify, INTUNE_TENANT_ID override, `is_current` unique enforcement, “Make current” action, block deactivated tenants. - **US6 Permissions/Health (Phase 9)**: Required permissions list, compare/check service, Verify action updates status and audit, permissions panel in Tenant detail. - **US1b Settings Display (Phase 13)**: PolicyNormalizer + SnapshotValidator, warnings for malformed snapshots, normalized settings and pretty JSON on policy/version detail, list badges, README section. +- **US7 RBAC Wizard (Phase 14)**: Delegated, synchronous onboarding wizard with post-verify canary checks and audit trail. +- **US8 Graph Contracts & Drift Guard (Phase 15)**: Config-driven contract registry, type-family handling, capability downgrade fallbacks, and a drift-check command. - **Housekeeping/UX (Phases 10–12)**: Soft/force deletes for tenants/backups/versions/restore runs with guards; table actions in ActionGroup per UX guideline. - **Ops (Phase 7)**: Sail runbook and Dokploy staging→prod guidance captured. -## Execution Plan: US7 Intune RBAC Onboarding Wizard (Phase 14) +## Completed: US7 Intune RBAC Onboarding Wizard (Phase 14) - Objectives: deliver delegated, tenant-scoped wizard that safely converges the Intune RBAC state for the configured service principal; fully audited, idempotent, least-privilege by default. - Scope alignment: FR-023–FR-030, constitution (Safety-First, Auditability, Tenant-Aware, Graph Abstraction). No secret/token persistence; delegated tokens stay request-local and are not stored in DB/cache. @@ -56,7 +58,7 @@ ## Execution Plan: US7 Intune RBAC Onboarding Wizard (Phase 14) - Health integration: Verify reflects RBAC status and prompts to run wizard when missing. - Deployment/ops: no new env vars; ensure migrations for tenant RBAC columns are applied; run targeted tests `php artisan test tests/Unit/RbacOnboardingServiceTest.php tests/Feature/Filament/TenantRbacWizardTest.php`; Pint on touched files. -## Upcoming: US8 Graph Contract Registry & Drift Guard (Phase 15) +## Completed: US8 Graph Contract Registry & Drift Guard (Phase 15) - Objectives: centralize Graph contract assumptions per supported type/endpoint and provide drift detection + safe fallbacks so preview/restore remain stable on Graph shape/capability changes. - Scope alignment: FR-031–FR-034 (spec), constitution (Safety-First, Auditability, Graph Abstraction, Tenant-Aware). @@ -74,7 +76,7 @@ ## Upcoming: US8 Graph Contract Registry & Drift Guard (Phase 15) - Testing outline: unit for registry lookups/type-family matching/fallback selection; integration/Pest to simulate capability errors and ensure downgrade path + correct routing for derived types. ## Testing & Quality Gates -- Continue using targeted Pest runs per change set; add/extend tests for US7 wizard now, and for US8 contracts when implemented. +- Continue using targeted Pest runs per change set; add/extend tests when RBAC/contract behavior changes. - Run Pint on touched files before finalizing. - Maintain tenant isolation, audit logging, and restore safety gates; validate snapshot shape and type-family compatibility prior to restore execution. @@ -83,6 +85,6 @@ ### Restore Safety Gate - Restore preview MAY still render details + warnings for out-of-family snapshots, but MUST NOT offer an apply action. ## Coordination -- Update `.specify/tasks.md` to reflect progress on US7 wizard and future US8 contract tasks; no new entities or scope changes introduced here. +- Keep `.specify/tasks.md` and per-feature specs under `specs/` aligned with implementation changes. - Stage validation required before production for any migration or restore-impacting change. -- Keep Graph integration behind abstraction; no secrets in logs; follow existing UX patterns (ActionGroup, warnings for risky ops). \ No newline at end of file +- Keep Graph integration behind abstraction; no secrets in logs; follow existing UX patterns (ActionGroup, warnings for risky ops). diff --git a/.specify/spec.md b/.specify/spec.md index 6ba9f44..e664e78 100644 --- a/.specify/spec.md +++ b/.specify/spec.md @@ -1,20 +1,46 @@ # Feature Specification: TenantPilot v1 -**Feature Branch**: `tenantpilot-v1` +**Feature Branch**: `dev` **Created**: 2025-12-10 -**Status**: Draft +**Status**: Active +**Last Updated**: 2026-01-03 **Input**: TenantPilot v1 scope covering Intune configuration inventory (config, compliance, scripts, apps, conditional access, endpoint security, enrollment/autopilot, RBAC), backup, version history, and defensive restore for Intune administrators. ## Scope ```yaml scope: - description: "v1 muss folgende Intune-Objekttypen inventarisieren, sichern und – je nach Risikoklasse – wiederherstellen können." + description: "v1 muss folgende Intune-Objekttypen inventarisieren, sichern und – je nach Risikoklasse – wiederherstellen können. Single Source of Truth: config/tenantpilot.php + config/graph_contracts.php." supported_types: - key: deviceConfiguration name: "Device Configuration" graph_resource: "deviceManagement/deviceConfigurations" - notes: "Inklusive Custom OMA-URI, Administrative Templates und Settings Catalog." + filter: "not isof('microsoft.graph.windowsUpdateForBusinessConfiguration')" + notes: "Standard Device Config inkl. Custom OMA-URI; excludes WUfB Update Rings." + + - key: groupPolicyConfiguration + name: "Administrative Templates" + graph_resource: "deviceManagement/groupPolicyConfigurations" + notes: "Administrative Templates (Group Policy)." + + - key: settingsCatalogPolicy + name: "Settings Catalog Policy" + graph_resource: "deviceManagement/configurationPolicies" + notes: "Settings Catalog policies; settings are hydrated from the /settings subresource." + + - key: windowsUpdateRing + name: "Software Update Ring" + graph_resource: "deviceManagement/deviceConfigurations" + filter: "isof('microsoft.graph.windowsUpdateForBusinessConfiguration')" + notes: "Windows Update for Business (WUfB) update rings." + + - key: windowsFeatureUpdateProfile + name: "Feature Updates (Windows)" + graph_resource: "deviceManagement/windowsFeatureUpdateProfiles" + + - key: windowsQualityUpdateProfile + name: "Quality Updates (Windows)" + graph_resource: "deviceManagement/windowsQualityUpdateProfiles" - key: deviceCompliancePolicy name: "Device Compliance" @@ -25,6 +51,16 @@ ## Scope graph_resource: "deviceAppManagement/managedAppPolicies" notes: "iOS und Android Managed App Protection." + - key: mamAppConfiguration + name: "App Configuration (MAM)" + graph_resource: "deviceAppManagement/targetedManagedAppConfigurations" + notes: "App configuration targeting managed apps (MAM)." + + - key: managedDeviceAppConfiguration + name: "App Configuration (Device)" + graph_resource: "deviceAppManagement/mobileAppConfigurations" + notes: "Managed device app configuration profiles." + - key: conditionalAccessPolicy name: "Conditional Access" graph_resource: "identity/conditionalAccess/policies" @@ -35,6 +71,14 @@ ## Scope graph_resource: "deviceManagement/deviceManagementScripts" notes: "scriptContent wird beim Backup base64-decoded gespeichert und beim Restore wieder encoded (vgl. FR-020)." + - key: deviceShellScript + name: "macOS Shell Scripts" + graph_resource: "deviceManagement/deviceShellScripts" + + - key: deviceHealthScript + name: "Proactive Remediations" + graph_resource: "deviceManagement/deviceHealthScripts" + - key: enrollmentRestriction name: "Enrollment Restrictions" graph_resource: "deviceManagement/deviceEnrollmentConfigurations" @@ -46,22 +90,40 @@ ## Scope - key: windowsEnrollmentStatusPage name: "Enrollment Status Page (ESP)" graph_resource: "deviceManagement/deviceEnrollmentConfigurations" - filter: "odata.type eq '#microsoft.graph.windows10EnrollmentCompletionPageConfiguration'" + notes: "Filtered to #microsoft.graph.windows10EnrollmentCompletionPageConfiguration." - key: endpointSecurityIntent name: "Endpoint Security Intents" graph_resource: "deviceManagement/intents" notes: "Account Protection, Disk Encryption etc.; Zuordnung über bekannte Templates." + - key: endpointSecurityPolicy + name: "Endpoint Security Policies" + graph_resource: "deviceManagement/configurationPolicies" + notes: "Configuration policies classified via technologies/templateReference; restore execution enabled with template validation (Feature 023)." + + - key: securityBaselinePolicy + name: "Security Baselines" + graph_resource: "deviceManagement/configurationPolicies" + notes: "High risk; v1 restore stays preview-only." + - key: mobileApp name: "Applications (Metadata only)" graph_resource: "deviceAppManagement/mobileApps" notes: "Backup nur von Metadaten/Zuweisungen (kein Binary-Download in v1)." - - key: settingsCatalogPolicy - name: "Settings Catalog Policy" - graph_resource: "deviceManagement/configurationPolicies" - notes: "Intune Settings Catalog Policies liegen NICHT unter deviceConfigurations, sondern unter configurationPolicies. v1 behandelt sie als eigenen Typ." + foundation_types: + - key: assignmentFilter + name: "Assignment Filter" + graph_resource: "deviceManagement/assignmentFilters" + + - key: roleScopeTag + name: "Scope Tag" + graph_resource: "deviceManagement/roleScopeTags" + + - key: notificationMessageTemplate + name: "Notification Message Template" + graph_resource: "deviceManagement/notificationMessageTemplates" restore_matrix: deviceConfiguration: @@ -70,6 +132,32 @@ ## Scope risk: medium notes: "Standard-Case für Backup+Restore; starke Preview/Audit Pflicht." + groupPolicyConfiguration: + backup: full + restore: enabled + risk: medium + + settingsCatalogPolicy: + backup: full + restore: enabled + risk: medium + notes: "Settings are applied via configurationPolicies/{id}/settings; capability fallbacks may require manual follow-up." + + windowsUpdateRing: + backup: full + restore: enabled + risk: medium-high + + windowsFeatureUpdateProfile: + backup: full + restore: enabled + risk: high + + windowsQualityUpdateProfile: + backup: full + restore: enabled + risk: high + deviceCompliancePolicy: backup: full restore: enabled @@ -82,6 +170,16 @@ ## Scope risk: medium-high notes: "MAM-Änderungen wirken auf Datenzugriff in Apps; Preview und Diff wichtig." + mamAppConfiguration: + backup: full + restore: enabled + risk: medium-high + + managedDeviceAppConfiguration: + backup: full + restore: enabled + risk: medium-high + conditionalAccessPolicy: backup: full restore: preview-only @@ -94,6 +192,16 @@ ## Scope risk: medium notes: "Script-Inhalt und Einstellungen werden gesichert; Decode/Encode beachten." + deviceShellScript: + backup: full + restore: enabled + risk: medium + + deviceHealthScript: + backup: full + restore: enabled + risk: medium + enrollmentRestriction: backup: full restore: preview-only @@ -118,17 +226,38 @@ ## Scope risk: high notes: "Security-relevante Einstellungen (z. B. Credential Guard); Preview + klare Konflikt-Warnungen nötig." - settingsCatalogPolicy: + endpointSecurityPolicy: backup: full - restore: enableds - risk: medium - notes: "Settings Catalog Policies sind Standard-Config-Policies (Settings Catalog). Preview/Audit Pflicht; Restore automatisierbar." + restore: enabled + risk: high + notes: "Enabled with template validation (Feature 023)." + + securityBaselinePolicy: + backup: full + restore: preview-only + risk: high + notes: "High risk; preview-only by default." mobileApp: backup: metadata-only restore: enabled risk: low-medium notes: "Nur Metadaten/Zuweisungen; kein Binary; Restore setzt Konfigurationen/Zuweisungen wieder." + + assignmentFilter: + backup: full + restore: enabled + risk: low + + roleScopeTag: + backup: full + restore: enabled + risk: low + + notificationMessageTemplate: + backup: full + restore: enabled + risk: low ``` ## User Scenarios & Testing *(mandatory)* diff --git a/.specify/tasks.md b/.specify/tasks.md index d369dae..701dd6f 100644 --- a/.specify/tasks.md +++ b/.specify/tasks.md @@ -8,9 +8,9 @@ # Tasks: TenantPilot v1 **Prerequisites**: plan.md (complete), spec.md (complete) **Status snapshot** -- Done: Phases 1–13 (US1–US4, Settings normalization/display, Highlander, US6 permissions/health, housekeeping/UX, ops) -- Next up: Phase 14 (US7) delegated Intune RBAC onboarding wizard (synchronous) -- Upcoming: Phase 15 (US8) Graph Contract Registry & Drift Guard +- Done: Phases 1–15 (US1–US8, Settings Catalog hydration/display, restore rerun, Highlander, US6 permissions/health, housekeeping/UX, ops) +- Open: T167 (optional) CLI/Job for CHECK/REPORT only (no grant) +- Next up: Feature 018 (Driver Updates / WUfB add-on) in `specs/018-driver-updates-wufb/` --- @@ -188,7 +188,7 @@ ## Acceptance Criteria - Restore von `settingsCatalogPolicy` scheitert nicht mehr an `Platforms`. - Results zeigen bei Fehlern weiterhin request-id/client-request-id (bleibt wie T177). -- [ ] T179 [US1b][Scope][settingsCatalogPolicy] Hydrate Settings Catalog “Configuration settings” for snapshots + normalized display +- [x] T179 [US1b][Scope][settingsCatalogPolicy] Hydrate Settings Catalog “Configuration settings” for snapshots + normalized display - **Goal:** Für `settingsCatalogPolicy` sollen die **Configuration settings** (wie im Intune Portal unter *Configuration settings*) im System sichtbar sein: - in **Policy Version Raw JSON** enthalten @@ -278,7 +278,7 @@ ## Verification -- [ ] T180 [US1b][Bug][settingsCatalogPolicy] Hydrate Settings Catalog settings in Version capture + Policy detail uses hydrated snapshot +- [x] T180 [US1b][Bug][settingsCatalogPolicy] Hydrate Settings Catalog settings in Version capture + Policy detail uses hydrated snapshot - **Goal:** `settingsCatalogPolicy` soll die *Configuration settings* nicht nur in Backups, sondern auch in **Policy Versions** enthalten, damit **Policy Detail**, Diff/Preview/Restore auf den echten Settings basieren. - **Why:** Aktuell hydriert nur `BackupService`, aber Policy Detail/Versions zeigen weiterhin nur Base-Metadaten. @@ -610,7 +610,7 @@ ## Acceptance Criteria -- [ ]T185 [UX][US1b][settingsCatalogPolicy] Make Settings Catalog settings readable (label/value parsing + table ergonomics) +- [x] T185 [UX][US1b][settingsCatalogPolicy] Make Settings Catalog settings readable (label/value parsing + table ergonomics) - **Goal:** Settings Catalog Policies sollen im Policy/Version Detail **für Admins lesbar** sein, ohne dass wir “alle Settings kennen müssen”. - Tabelle zeigt **sprechende Bezeichnung** + **kompakte Werte** @@ -699,7 +699,7 @@ ## Acceptance Criteria - **Readable Setting name** (not a cut-off vendor string) - **Readable Value preview** (True/False/12/etc.) -- [ ] T186 [US4][Bugfix][settingsCatalogPolicy] Fix settings_apply payload typing (@odata.type) + body shape for configurationPolicies/{id}/settings +- [x] T186 [US4][Bugfix][settingsCatalogPolicy] Fix settings_apply payload typing (@odata.type) + body shape for configurationPolicies/{id}/settings **Goal:** Restore für `settingsCatalogPolicy` soll Settings zuverlässig anwenden können, ohne ModelValidationFailure wegen fehlender/entfernter `@odata.type`. @@ -787,7 +787,7 @@ ### Implementation for User Story 4 - [x] T023 [US4] Implement restore service with preview/dry-run and selective item application in `app/Services/Intune/RestoreService.php`, integrating Graph adapter and conflict detection. - [x] T024 [US4] Add Filament restore UI (wizard or pages) showing preview, warnings, and confirmation gate in `app/Filament/Resources/RestoreRunResource.php`. - [x] T025 [US4] Record restore run lifecycle (start, per-item result, completion) and audit events in `restore_runs` and `audit_logs`. -- [ ] T156 [US4][UX] Add “Rerun” action to RestoreRun row actions (ActionGroup): creates a new RestoreRun cloned from selected run (same backup_set_id, same selected items, same dry_run flag), enforces same safety gates/confirmations as original execution path, writes audit event restore_run.rerun_created with source_restore_run_id. +- [x] T156 [US4][UX] Add “Rerun” action to RestoreRun row actions (ActionGroup): creates a new RestoreRun cloned from selected run (same backup_set_id, same selected items, same dry_run flag), enforces same safety gates/confirmations as original execution path, writes audit event restore_run.rerun_created with source_restore_run_id. ## Phase 7: User Story 5 - Operational readiness and environments (Priority: P2) diff --git a/specs/018-driver-updates-wufb/checklists/requirements.md b/specs/018-driver-updates-wufb/checklists/requirements.md new file mode 100644 index 0000000..2186975 --- /dev/null +++ b/specs/018-driver-updates-wufb/checklists/requirements.md @@ -0,0 +1,15 @@ +# Requirements Checklist (018) + +**Created**: 2026-01-03 +**Feature**: [spec.md](../spec.md) + +- [ ] `windowsDriverUpdateProfile` is added to `config/tenantpilot.php` (metadata, endpoint, backup/restore mode, risk). +- [ ] Graph contract exists in `config/graph_contracts.php` (resource, type family, create/update methods, assignments paths). +- [ ] Sync lists and stores driver update profiles in the Policies inventory. +- [ ] Snapshot capture stores a complete payload for backups and versions. +- [ ] Restore preview is available and respects the configured restore mode. +- [ ] Restore execution applies only patchable properties and records audit logs. +- [ ] Normalized settings view is readable for admins (no raw-only UX). +- [ ] Pest tests cover sync + snapshot + restore + normalized display. +- [ ] Pint run (`./vendor/bin/pint --dirty`) on touched files. + diff --git a/specs/018-driver-updates-wufb/plan.md b/specs/018-driver-updates-wufb/plan.md new file mode 100644 index 0000000..1b26dda --- /dev/null +++ b/specs/018-driver-updates-wufb/plan.md @@ -0,0 +1,24 @@ +# Plan: Driver Updates (WUfB Add-on) (018) + +**Branch**: `feat/018-driver-updates-wufb` +**Date**: 2026-01-03 +**Input**: [spec.md](./spec.md) + +## Goal +Add first-class support for Windows Driver Update profiles (`windowsDriverUpdateProfile`) across inventory, backup/version snapshots, restore (preview + execution), and normalized display. + +## Approach +1. Confirm Graph API details for driver update profiles (resource path, `@odata.type`, patchable properties, assignment endpoints). +2. Add type metadata to `config/tenantpilot.php` (category, endpoint, backup/restore mode, risk). +3. Add Graph contract entry in `config/graph_contracts.php` (resource, type family, create/update methods, assignments). +4. Ensure sync lists and stores these policies (config-driven loop) and add a targeted sync test. +5. Ensure snapshots capture the complete payload and add tests for version/backup capture. +6. Implement restore apply via contract-driven sanitization; add failure-safe behavior and tests. +7. Add a normalizer for readable UI output; add tests for normalized display. +8. Run Pint and targeted tests. + +## Decisions / Notes +- Default to contract-driven restore semantics; avoid bespoke Graph calls unless strictly required. +- If Graph rejects PATCH due to read-only fields, extend `update_strip_keys` for this type (do not loosen safety). +- Keep restore risk high; require clear preview and audit trail. + diff --git a/specs/018-driver-updates-wufb/spec.md b/specs/018-driver-updates-wufb/spec.md new file mode 100644 index 0000000..d5315e0 --- /dev/null +++ b/specs/018-driver-updates-wufb/spec.md @@ -0,0 +1,77 @@ +# Feature Specification: Driver Updates (WUfB Add-on) (018) + +**Feature Branch**: `feat/018-driver-updates-wufb` +**Created**: 2026-01-03 +**Status**: Draft +**Priority**: P1 + +## Context +TenantPilot already covers core Windows Update for Business (WUfB) objects like: +- Update Rings (`windowsUpdateRing`) +- Feature Update Profiles (`windowsFeatureUpdateProfile`) +- Quality Update Profiles (`windowsQualityUpdateProfile`) + +This feature adds **Windows Driver Updates** coverage to the same Update Management area so driver rollout configuration can be inventoried, snapshotted, diffed, and restored safely. + +## In Scope +- New policy type: `windowsDriverUpdateProfile` +- Inventory/sync: list driver update profiles from Microsoft Graph and store them as policies. +- Snapshot capture: full snapshot of the profile payload (and assignments where supported). +- Restore: + - Preview/dry-run with diff + risk checks. + - Execution (PATCH/POST) as allowed by Graph, with audit logging. +- UI: normalized settings display (readable, admin-focused). + +## Out of Scope (v1) +- Per-driver approval workflows / driver inventory insights. +- Advanced reporting on driver compliance. +- Partial per-setting restore. + +## Graph API Assumptions (to verify) +- **Resource**: `deviceManagement/windowsDriverUpdateProfiles` +- **@odata.type**: `#microsoft.graph.windowsDriverUpdateProfile` +- **Assignments**: standard pattern with: + - list: `/deviceManagement/windowsDriverUpdateProfiles/{id}/assignments` + - assign action: `/deviceManagement/windowsDriverUpdateProfiles/{id}/assign` + +## User Scenarios & Testing + +### User Story 1 — Inventory + readable view (P1) +As an admin, I can see Windows Driver Update profiles in the Policies list and view their configuration in a readable way. + +**Acceptance** +1. Driver update profiles appear in the policy inventory with the correct type and category. +2. Policy detail shows a normalized settings table (not only raw JSON). +3. Policy Versions render “Normalized settings” consistently. + +### User Story 2 — Snapshot capture (P1) +As an admin, when I capture a version or add a driver update profile to a backup set, the snapshot contains all relevant settings. + +**Acceptance** +1. Snapshot stores the full Graph payload in JSON (immutable). +2. Any non-patchable/read-only properties are still preserved in the snapshot (but not sent on restore). + +### User Story 3 — Restore preview + execution (P1) +As an admin, I can restore a driver update profile from a snapshot with a clear preview and safe execution. + +**Acceptance** +1. Preview shows what would change and blocks if risk checks fail. +2. Execution applies only patchable properties (contract-driven sanitization). +3. Restore results include Graph error details (request-id, client-request-id, path/method) on failure. + +## Requirements + +### Functional Requirements +- **FR-001**: Add `windowsDriverUpdateProfile` to `config/tenantpilot.php` with category “Update Management”. +- **FR-002**: Add Graph contract entry for `windowsDriverUpdateProfile` in `config/graph_contracts.php` (resource, type family, create/update methods, assignments paths). +- **FR-003**: Ensure `PolicySyncService` syncs driver update profiles via config-driven type list. +- **FR-004**: Ensure `PolicySnapshotService` captures a complete payload for this type. +- **FR-005**: Ensure `RestoreService` applies snapshots using contract-driven sanitization and audit logging. +- **FR-006**: Add normalized display support for the key driver update profile fields. +- **FR-007**: Add automated Pest tests for sync + snapshot + restore preview/execution. + +### Non-Functional Requirements +- **NFR-001**: Preserve tenant isolation and least privilege. +- **NFR-002**: Keep restore safe-by-default (preview/confirmation/audit). +- **NFR-003**: No new external services or dependencies. + diff --git a/specs/018-driver-updates-wufb/tasks.md b/specs/018-driver-updates-wufb/tasks.md new file mode 100644 index 0000000..b6bcc69 --- /dev/null +++ b/specs/018-driver-updates-wufb/tasks.md @@ -0,0 +1,32 @@ +# Tasks: Driver Updates (WUfB Add-on) (018) + +**Branch**: `feat/018-driver-updates-wufb` +**Date**: 2026-01-03 +**Input**: [spec.md](./spec.md), [plan.md](./plan.md) + +## Phase 1: Setup +- [x] T001 Create/confirm spec, plan, tasks, checklist. + +## Phase 2: Research & Design +- [ ] T002 Verify Graph resource + `@odata.type` for driver update profiles. +- [ ] T003 Verify PATCHable fields and define `update_strip_keys` / `update_whitelist`. +- [ ] T004 Verify assignment endpoints (`/assignments`, `/assign`) for this resource. +- [ ] T005 Decide restore mode (`enabled` vs `preview-only`) based on risk + patchability. + +## Phase 3: Tests (TDD) +- [ ] T006 Add sync test ensuring `windowsDriverUpdateProfile` policies are imported and typed correctly. +- [ ] T007 Add snapshot/version capture test asserting full payload is stored. +- [ ] T008 Add restore preview test for this type (entries + restore_mode shown). +- [ ] T009 Add restore execution test asserting only patchable properties are sent and failures are reported with Graph metadata. +- [ ] T010 Add normalized display test for key fields. + +## Phase 4: Implementation +- [ ] T011 Add `windowsDriverUpdateProfile` to `config/tenantpilot.php`. +- [ ] T012 Add Graph contract entry in `config/graph_contracts.php`. +- [ ] T013 Implement any required snapshot hydration (if Graph uses subresources). +- [ ] T014 Implement restore apply support in `RestoreService` (contract-driven sanitization). +- [ ] T015 Add a `WindowsDriverUpdateProfileNormalizer` and register it. + +## Phase 5: Verification +- [ ] T016 Run targeted tests. +- [ ] T017 Run Pint (`./vendor/bin/pint --dirty`). diff --git a/specs/023-endpoint-security-restore/checklists/requirements.md b/specs/023-endpoint-security-restore/checklists/requirements.md index 2da1d80..7984f8a 100644 --- a/specs/023-endpoint-security-restore/checklists/requirements.md +++ b/specs/023-endpoint-security-restore/checklists/requirements.md @@ -3,12 +3,11 @@ # Requirements Checklist (023) **Created**: 2026-01-03 **Feature**: [spec.md](../spec.md) -- [ ] `endpointSecurityPolicy.restore` is changed to `enabled` in `config/tenantpilot.php`. -- [ ] Restore preview validates template existence and reports missing/ambiguous templates. -- [ ] Restore execution blocks on missing/ambiguous templates with a clear, actionable error message. -- [ ] Settings instances are validated against resolved template definitions before execution. -- [ ] Template mapping strategy is defined for cross-tenant differences (if required) and is tested. -- [ ] Restore create + update paths for Endpoint Security policies are covered by automated tests. -- [ ] Assignments mapping/application for Endpoint Security policies are covered by automated tests. -- [ ] Audit log entries exist for restore execution attempts (success and failure). - +- [x] `endpointSecurityPolicy.restore` is changed to `enabled` in `config/tenantpilot.php`. +- [x] Restore preview validates template existence and reports missing/ambiguous templates. +- [x] Restore execution blocks on missing/ambiguous templates with a clear, actionable error message. +- [x] Settings instances are validated against resolved template definitions before execution. +- [x] Template mapping strategy is defined for cross-tenant differences (if required) and is tested. +- [x] Restore create + update paths for Endpoint Security policies are covered by automated tests. +- [x] Assignments mapping/application for Endpoint Security policies are covered by automated tests. +- [x] Audit log entries exist for restore execution attempts (success and failure). diff --git a/specs/023-endpoint-security-restore/plan.md b/specs/023-endpoint-security-restore/plan.md index c843861..8109384 100644 --- a/specs/023-endpoint-security-restore/plan.md +++ b/specs/023-endpoint-security-restore/plan.md @@ -3,6 +3,7 @@ # Plan: Endpoint Security Policy Restore (023) **Branch**: `feat/023-endpoint-security-restore` **Date**: 2026-01-03 **Input**: [spec.md](./spec.md) +**Status**: Implemented (ready to merge) ## Goal Enable full restore execution for Endpoint Security Policies (`endpointSecurityPolicy`) instead of preview-only, with defensive validation around templates and settings payloads. @@ -29,4 +30,4 @@ ## Approach ## Decisions / Notes - Assume template identifiers may differ across tenants; prefer mapping by `templateFamily` with display-name fallback when required. - Safety-first: if template resolution is ambiguous, treat as missing and block execution. - + - Incident hardening: make restore failures actionable by surfacing Graph path/method and avoid unsafe fallback endpoints. diff --git a/specs/023-endpoint-security-restore/spec.md b/specs/023-endpoint-security-restore/spec.md index 81b3fd5..c8cfe5f 100644 --- a/specs/023-endpoint-security-restore/spec.md +++ b/specs/023-endpoint-security-restore/spec.md @@ -2,13 +2,13 @@ # Feature Specification: Enable Endpoint Security Policy Restore (023) **Feature Branch**: `feat/023-endpoint-security-restore` **Created**: 2026-01-03 -**Status**: Draft +**Status**: Implemented (ready to merge) **Priority**: P1 (Quick Win) ## Context Endpoint Security Policies are already in the `tenantpilot.php` config as `endpointSecurityPolicy` with `restore => 'preview-only'`. Based on Microsoft's recommendation to use the unified `deviceManagement/configurationPolicies` endpoint (over the deprecated `intents` API for new creations), we should enable full restore for this type. -This is a **configuration-only change** with additional validation/testing, not a new policy type implementation. +This is a **restore-mode enablement** with additional validation/testing and targeted restore hardening, not a new policy type implementation. ## User Scenarios & Testing diff --git a/specs/023-endpoint-security-restore/tasks.md b/specs/023-endpoint-security-restore/tasks.md index 049479b..5142e65 100644 --- a/specs/023-endpoint-security-restore/tasks.md +++ b/specs/023-endpoint-security-restore/tasks.md @@ -8,25 +8,30 @@ ## Phase 1: Setup - [x] T001 Create spec/plan/tasks and checklist. ## Phase 2: Inventory & Design -- [ ] T002 Confirm current restore mode + code paths for `endpointSecurityPolicy` (`config/tenantpilot.php`, restore services). -- [ ] T003 Decide template resolution strategy (ID vs family/display name) and required Graph calls. -- [ ] T004 Define settings instance validation rules (warning vs block) for restore preview/execution. +- [x] T002 Confirm current restore mode + code paths for `endpointSecurityPolicy` (`config/tenantpilot.php`, restore services). +- [x] T003 Decide template resolution strategy (ID vs family/display name) and required Graph calls. +- [x] T004 Define settings instance validation rules (warning vs block) for restore preview/execution. ## Phase 3: Tests (TDD) -- [ ] T005 Add feature tests for restore execution create/update for `endpointSecurityPolicy`. -- [ ] T006 Add feature tests for preview warnings when template is missing. -- [ ] T007 Add feature tests asserting restore execution fails gracefully when template is missing. -- [ ] T008 Add tests for settings validation failure paths (invalid/unknown settings instances). -- [ ] T009 Add feature tests asserting assignments are applied for endpoint security policies. +- [x] T005 Add feature tests for restore execution create/update for `endpointSecurityPolicy`. +- [x] T006 Add feature tests for preview warnings when template is missing. +- [x] T007 Add feature tests asserting restore execution fails gracefully when template is missing. +- [x] T008 Add tests for settings validation failure paths (invalid/unknown settings instances). +- [x] T009 Add feature tests asserting assignments are applied for endpoint security policies. ## Phase 4: Implementation -- [ ] T010 Enable restore for `endpointSecurityPolicy` in `config/tenantpilot.php`. -- [ ] T011 Implement template existence validation in restore preview and execution gating. -- [ ] T012 Implement settings instance validation against resolved template definitions. -- [ ] T013 Implement template mapping (if required) and ensure restore payload uses mapped template reference. -- [ ] T014 Ensure restore applies assignments for endpoint security policies using existing mapping logic. +- [x] T010 Enable restore for `endpointSecurityPolicy` in `config/tenantpilot.php`. +- [x] T011 Implement template existence validation in restore preview and execution gating. +- [x] T012 Implement settings instance validation against resolved template definitions. +- [x] T013 Implement template mapping (if required) and ensure restore payload uses mapped template reference. +- [x] T014 Ensure restore applies assignments for endpoint security policies using existing mapping logic. ## Phase 5: Verification -- [ ] T015 Run targeted tests. -- [ ] T016 Run Pint (`./vendor/bin/pint --dirty`). +- [x] T015 Run targeted tests. +- [x] T016 Run Pint (`./vendor/bin/pint --dirty`). +## Phase 6: Hardening (Incident-driven) +- [x] T017 Default unknown policy types to `preview-only` to avoid invalid Graph endpoints. +- [x] T018 Harden endpoint resolution fallback for configuration policy types (avoid `deviceManagement/{policyType}`). +- [x] T019 Surface Graph method/path in RestoreRun Results for faster debugging. +- [x] T020 Strip non-patchable fields for `endpointSecurityIntent` PATCH (`isAssigned`, `templateId`, `isMigratingToConfigurationPolicy`).