TenantAtlas/specs/006-sot-foundations-assignments/research.md
2025-12-25 14:52:28 +01:00

5.2 KiB

Research: SoT Foundations & Assignments (006)

This document resolves planning unknowns and records decisions for implementing foundations-first backup/restore and assignment-aware restore.

Decision: Foundation object endpoints and permissions

  • Decision: Implement “foundation” backup/restore for:
    • Assignment Filters via deviceManagement/assignmentFilters (permission: DeviceManagementConfiguration.ReadWrite.All).
    • Scope Tags via deviceManagement/roleScopeTags (permission: DeviceManagementRBAC.ReadWrite.All).
    • Notification Message Templates via deviceManagement/notificationMessageTemplates (permission: DeviceManagementServiceConfig.ReadWrite.All, with localizedNotificationMessages treated as a future enhancement).
  • Rationale: These are explicitly called out as SoT foundations and appear as dependencies in the IntuneManagement reference implementation.
  • Alternatives considered:
    • Treat foundations as “manual prerequisites” only (no backup/restore) → rejected because it blocks safe assignment restore.
    • Store only names (no full payload) → rejected because restore needs full object definitions.

Decision: Assignment apply mechanism (Graph)

  • Decision: Apply assignments using a per-resource .../{id}/assign Graph action (default), with request body shape:

    {
      "assignments": [
        {
          "target": {
            "@odata.type": "...",
            "groupId": "...",
            "deviceAndAppManagementAssignmentFilterId": "...",
            "deviceAndAppManagementAssignmentFilterType": "Include|Exclude"
          }
        }
      ]
    }
    

    and support type-specific overrides if needed.

  • Rationale: Matches the IntuneManagement import approach and aligns with SoT “apply assignments after foundations exist”.

  • Alternatives considered:

    • PATCH the resource with an assignments property → rejected because many Intune resources do not support assignment updates via PATCH.
    • Only restore object payloads, never assignments → rejected (SoT requires assignment-aware restore).

Decision: Mapping strategy (deterministic, safe)

  • Decision: Produce and persist an “old → new” mapping for foundation objects by matching primarily on displayName (or name-equivalent), with collision handling:
    • If a unique match exists in the target tenant by name: reuse (map old → existing).
    • If no match exists: create (map old → created).
    • If multiple matches exist: create a copy with a predictable suffix and record “created_copy” in the report.
  • Rationale: SoT requires determinism and auditability; mapping by opaque IDs is impossible across tenants.
  • Alternatives considered:
    • Always create new objects regardless of matches → rejected due to duplication and name collision risk.
    • Hash-based matching (normalize and compare multiple fields) → deferred; start with name-based plus explicit collision handling.

Decision: Where to store mappings and restore decision report

  • Decision: Store mapping + decisions in restore_runs.preview (dry-run) and restore_runs.results (execute), optionally mirrored into restore_runs.metadata for fast access.
  • Rationale: The schema already supports JSON preview/results; this keeps the first iteration simple and audit-friendly.
  • Alternatives considered:
    • Dedicated restore_mappings table → deferred until querying/reporting requirements demand it.

Decision: How to represent foundation snapshots in storage

  • Decision: Store foundation snapshots as backup_items rows with:
    • policy_id = null
    • policy_type set to a dedicated type key (e.g. assignmentFilter, roleScopeTag, notificationMessageTemplate)
    • policy_identifier set to the Graph object id
    • payload containing the raw Graph resource
    • metadata containing normalized identifiers used for matching (e.g. displayName).
  • Rationale: backup_items.policy_id is nullable; reusing the same snapshot container avoids schema churn.
  • Alternatives considered:
    • New “foundation_snapshots” table → rejected for MVP due to extra migrations and duplication.

Decision: Conditional Access restore behavior (safety)

  • Decision: Keep Conditional Access restore as preview-only, even in execute mode.
  • Rationale: CA depends on identity objects (e.g., named locations) and is security-critical; SoT explicitly allows preview-first for risky items.
  • Alternatives considered:
    • Allow CA restore with best-effort group/user mapping → rejected as too risky without complete dependency mapping.

Decision: Scope for assignment-aware restore (initial)

  • Decision: Apply assignment mapping for existing supported configuration objects (policy types already in config/tenantpilot.php), focusing first on targets that include:
    • group targeting (groupId)
    • assignment filters (deviceAndAppManagementAssignmentFilterId/Type)
    • role scope tags (roleScopeTagIds) where applicable.
  • Rationale: Incrementally delivers value without requiring support for all object classes in SoT.
  • Alternatives considered:
    • Expand to named locations / terms of use / authentication strengths immediately → deferred (separate dependency set).