feat/004-assignments-scope-tags #4
@ -183,12 +183,18 @@ ### Restore with Group Mapping
|
|||||||
**FR-004.11**: System MUST persist group mapping selections in RestoreRun metadata for audit and rerun purposes.
|
**FR-004.11**: System MUST persist group mapping selections in RestoreRun metadata for audit and rerun purposes.
|
||||||
|
|
||||||
**FR-004.12**: When restoring assignments, system MUST:
|
**FR-004.12**: When restoring assignments, system MUST:
|
||||||
1. Replace source group IDs with mapped target group IDs
|
1. Replace source group IDs with mapped target group IDs in assignment objects
|
||||||
2. Skip assignments marked "Skip"
|
2. Skip assignments marked "Skip" in group mapping
|
||||||
3. Preserve include/exclude intent and filters
|
3. Preserve include/exclude intent and filters
|
||||||
4. Call POST `/deviceManagement/configurationPolicies/{id}/assign` (not PATCH) with complete mapped assignments array (replaces all assignments atomically)
|
4. Execute restore via DELETE-then-CREATE pattern:
|
||||||
5. Handle 204 No Content or 200 OK as success
|
- Step 1: GET existing assignments from target policy
|
||||||
6. Log Graph request-id and client-request-id on failure
|
- Step 2: DELETE each existing assignment (via DELETE `/assignments/{id}`)
|
||||||
|
- Step 3: POST each new/mapped assignment (via POST `/assignments`)
|
||||||
|
5. Handle failures gracefully:
|
||||||
|
- 204 No Content on DELETE = success
|
||||||
|
- 201 Created on POST = success
|
||||||
|
- Log request-id/client-request-id on any failure
|
||||||
|
6. Continue with remaining assignments if one fails (fail-soft)
|
||||||
|
|
||||||
**FR-004.13**: System MUST handle assignment restore failures gracefully:
|
**FR-004.13**: System MUST handle assignment restore failures gracefully:
|
||||||
- Log per-assignment outcome (success/skip/failure)
|
- Log per-assignment outcome (success/skip/failure)
|
||||||
@ -274,26 +280,31 @@ ### Endpoints to Add (Production-Tested Strategies)
|
|||||||
- Client-side filter to extract assignments
|
- Client-side filter to extract assignments
|
||||||
- **Reason**: Known Graph API quirks with assignment expansion on certain template families
|
- **Reason**: Known Graph API quirks with assignment expansion on certain template families
|
||||||
|
|
||||||
2. **POST** `/deviceManagement/configurationPolicies/{id}/assign` (POST only, NOT PATCH)
|
2. **Assignment CRUD Operations** (Standard Graph Pattern)
|
||||||
- Body: `{ assignments: [assignment objects] }`
|
|
||||||
- Returns: 204 No Content or 200 OK
|
- **POST** `/deviceManagement/configurationPolicies/{id}/assignments`
|
||||||
- **Note**: This is an action endpoint, replaces entire assignments array
|
- Body: Single assignment object
|
||||||
- Example payload:
|
- Returns: 201 Created with assignment object
|
||||||
|
- Example:
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"assignments": [
|
|
||||||
{
|
|
||||||
"id": "00000000-0000-0000-0000-000000000000",
|
|
||||||
"target": {
|
"target": {
|
||||||
"@odata.type": "#microsoft.graph.groupAssignmentTarget",
|
"@odata.type": "#microsoft.graph.groupAssignmentTarget",
|
||||||
"groupId": "abc-123-def"
|
"groupId": "abc-123-def"
|
||||||
},
|
},
|
||||||
"intent": "apply"
|
"intent": "apply"
|
||||||
}
|
}
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
- **PATCH** `/deviceManagement/configurationPolicies/{id}/assignments/{assignmentId}`
|
||||||
|
- Body: Assignment object (partial update)
|
||||||
|
- Returns: 200 OK with updated assignment
|
||||||
|
|
||||||
|
- **DELETE** `/deviceManagement/configurationPolicies/{id}/assignments/{assignmentId}`
|
||||||
|
- Returns: 204 No Content
|
||||||
|
|
||||||
|
- **Restore Strategy**: DELETE all existing assignments, then POST new ones (atomic via transaction pattern)
|
||||||
|
|
||||||
3. **POST** `/directoryObjects/getByIds` (Stable Group Resolution)
|
3. **POST** `/directoryObjects/getByIds` (Stable Group Resolution)
|
||||||
- Body: `{ "ids": ["id1", "id2"], "types": ["group"] }`
|
- Body: `{ "ids": ["id1", "id2"], "types": ["group"] }`
|
||||||
- Returns: `{ value: [{ id, displayName, ... }] }`
|
- Returns: `{ value: [{ id, displayName, ... }] }`
|
||||||
@ -316,11 +327,20 @@ ### Graph Contract Updates
|
|||||||
|
|
||||||
```php
|
```php
|
||||||
'settingsCatalogPolicy' => [
|
'settingsCatalogPolicy' => [
|
||||||
// ... existing
|
// ... existing config
|
||||||
'assignments_path' => '/deviceManagement/configurationPolicies/{id}/assignments',
|
|
||||||
'assign_method' => 'POST',
|
// Assignments CRUD (standard Graph pattern)
|
||||||
'assign_path' => '/deviceManagement/configurationPolicies/{id}/assign',
|
'assignments_list_path' => '/deviceManagement/configurationPolicies/{id}/assignments',
|
||||||
|
'assignments_create_path' => '/deviceManagement/configurationPolicies/{id}/assignments',
|
||||||
|
'assignments_create_method' => 'POST',
|
||||||
|
'assignments_update_path' => '/deviceManagement/configurationPolicies/{id}/assignments/{assignmentId}',
|
||||||
|
'assignments_update_method' => 'PATCH',
|
||||||
|
'assignments_delete_path' => '/deviceManagement/configurationPolicies/{id}/assignments/{assignmentId}',
|
||||||
|
'assignments_delete_method' => 'DELETE',
|
||||||
|
|
||||||
|
// Scope Tags
|
||||||
'supports_scope_tags' => true,
|
'supports_scope_tags' => true,
|
||||||
|
'scope_tag_field' => 'roleScopeTagIds', // array in policy payload
|
||||||
],
|
],
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user