fix(spec-004): Use documented CRUD on /assignments instead of undocumented /assign
Changes: - Replace POST /assign with standard CRUD operations - Restore strategy: DELETE existing + POST new assignments - Graph Contract: assignments_create/update/delete_path + methods - Handle 201 Created (POST) and 204 No Content (DELETE) - Fail-soft: continue if individual assignment fails Based on: Microsoft Learn Graph API docs + real-world usage patterns
This commit is contained in:
parent
1fa15b4db2
commit
28f440718a
@ -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.12**: When restoring assignments, system MUST:
|
||||
1. Replace source group IDs with mapped target group IDs
|
||||
2. Skip assignments marked "Skip"
|
||||
1. Replace source group IDs with mapped target group IDs in assignment objects
|
||||
2. Skip assignments marked "Skip" in group mapping
|
||||
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)
|
||||
5. Handle 204 No Content or 200 OK as success
|
||||
6. Log Graph request-id and client-request-id on failure
|
||||
4. Execute restore via DELETE-then-CREATE pattern:
|
||||
- Step 1: GET existing assignments from target policy
|
||||
- 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:
|
||||
- Log per-assignment outcome (success/skip/failure)
|
||||
@ -274,25 +280,30 @@ ### Endpoints to Add (Production-Tested Strategies)
|
||||
- Client-side filter to extract assignments
|
||||
- **Reason**: Known Graph API quirks with assignment expansion on certain template families
|
||||
|
||||
2. **POST** `/deviceManagement/configurationPolicies/{id}/assign` (POST only, NOT PATCH)
|
||||
- Body: `{ assignments: [assignment objects] }`
|
||||
- Returns: 204 No Content or 200 OK
|
||||
- **Note**: This is an action endpoint, replaces entire assignments array
|
||||
- Example payload:
|
||||
```json
|
||||
{
|
||||
"assignments": [
|
||||
{
|
||||
"id": "00000000-0000-0000-0000-000000000000",
|
||||
"target": {
|
||||
"@odata.type": "#microsoft.graph.groupAssignmentTarget",
|
||||
"groupId": "abc-123-def"
|
||||
},
|
||||
"intent": "apply"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
2. **Assignment CRUD Operations** (Standard Graph Pattern)
|
||||
|
||||
- **POST** `/deviceManagement/configurationPolicies/{id}/assignments`
|
||||
- Body: Single assignment object
|
||||
- Returns: 201 Created with assignment object
|
||||
- Example:
|
||||
```json
|
||||
{
|
||||
"target": {
|
||||
"@odata.type": "#microsoft.graph.groupAssignmentTarget",
|
||||
"groupId": "abc-123-def"
|
||||
},
|
||||
"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)
|
||||
- Body: `{ "ids": ["id1", "id2"], "types": ["group"] }`
|
||||
@ -316,11 +327,20 @@ ### Graph Contract Updates
|
||||
|
||||
```php
|
||||
'settingsCatalogPolicy' => [
|
||||
// ... existing
|
||||
'assignments_path' => '/deviceManagement/configurationPolicies/{id}/assignments',
|
||||
'assign_method' => 'POST',
|
||||
'assign_path' => '/deviceManagement/configurationPolicies/{id}/assign',
|
||||
// ... existing config
|
||||
|
||||
// Assignments CRUD (standard Graph pattern)
|
||||
'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,
|
||||
'scope_tag_field' => 'roleScopeTagIds', // array in policy payload
|
||||
],
|
||||
```
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user