87 lines
5.2 KiB
Markdown
87 lines
5.2 KiB
Markdown
# 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:
|
|
|
|
```json
|
|
{
|
|
"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).
|