TenantAtlas/specs/009-app-protection-policy/spec.md
ahmido fbb9748725 feat/009-app-protection-policy (#11)
Summary

add appProtectionPolicy coverage for assignments, normalize settings for UI, and skip targetedManagedAppConfiguration noise during inventory
wire up derived Graph endpoints/contracts so restores use the correct /assign paths per platform and assignments no longer rely on unsupported $expand
add normalization logic/tests plus Pact/Plan updates so capture+restore behave more like Intune’s app protection workflows and no longer expose unsupported fields

Co-authored-by: Ahmed Darrazi <ahmeddarrazi@adsmac.local>
Reviewed-on: #11
2025-12-29 16:11:50 +00:00

3.5 KiB
Raw Permalink Blame History

Feature Specification: App Protection (MAM) Policy Type Coverage

Feature Branch: feat/009-app-protection-policy
Created: 2025-12-29
Status: Draft

Overview

Make App Protection (MAM) policies (appProtectionPolicy) reliable in TenantAtlas existing Policy/Backup/Restore flows by:

  • Preventing non-policy objects (Managed App Configurations) from being imported as policies during sync.
  • Capturing and restoring assignments for managedAppPolicies.
  • Expanding the accepted @odata.type family so restore/create flows dont fail with false odata_mismatch.
  • Improving admin readability by normalizing key settings (booleans/durations) into Intune-like sections.

In Scope

  • Policy type: appProtectionPolicy (deviceAppManagement/managedAppPolicies)
  • Policy sync: skip objects with @odata.type == #microsoft.graph.targetedManagedAppConfiguration
  • Backup/version capture: capture assignments when enabled
  • Restore: reapply assignments using /assign with group + assignment filter mapping (existing mapping UI)
  • UI: normalize App Protection snapshots for readability (bool/duration formatting + grouped sections)

Out of Scope (v1)

  • “Target apps” (/targetApps) workflows for App Protection objects (showing the actual app list like Intune).
  • Full “create from scratch” for missing App Protection policies (beyond generic create fallback).
  • Separately modeling App Configurations (targetedManagedAppConfigurations) as their own policy type.

User Scenarios & Testing (mandatory)

User Story 1 — Clean Inventory (P1)

As an admin, I want the App Protection policy list to only include actual protection policies (not app configurations), so inventory stays accurate.

Independent Test: Run policy sync; confirm targetedManagedAppConfiguration objects do not appear as appProtectionPolicy records.

Acceptance Scenarios

  1. Given Graph returns mixed objects from managedAppPolicies, when sync runs, then items with @odata.type == #microsoft.graph.targetedManagedAppConfiguration are skipped.

User Story 2 — Backup assignments (P1)

As an admin, I can capture App Protection assignments during backup/version capture, so restore can reproduce targeting.

Independent Test: Capture a backup set with assignments enabled; verify assignments are saved for App Protection policies.

Acceptance Scenarios

  1. Given assignments are enabled, when capturing an App Protection snapshot, then assignments are fetched via the configured assignments endpoint and stored on the version/item.

User Story 3 — Restore assignments (P1)

As an admin, I can restore App Protection assignments using group mapping with clear skip/failure reasons.

Independent Test: Restore an App Protection backup into a tenant with different group IDs; verify assignments are created/skipped with expected outcomes.

Acceptance Scenarios

  1. Given group mapping is present, when restore executes, then assignments are applied via /assign.
  2. Given group mapping is missing for a group, when restore executes, then that assignment is skipped with a clear reason.

Notes

  • Filtering is implemented in code because Graph filtering does not reliably exclude targetedManagedAppConfiguration objects from the managedAppPolicies list response.
  • @odata.type matching uses config/graph_contracts.php as the safety gate for create flows.
  • Assignments restore uses derived endpoints (e.g. /deviceAppManagement/androidManagedAppProtections/{id}/assign) based on @odata.type for compatibility.