Skip to content

Commit 98c7ba7

Browse files
committed
fix(google-workspace-admin): fail the ChromeOS batch when a device does not change
batchChangeStatus returns HTTP 200 for the batch as a whole and reports each device separately, so a device that stayed enabled is only visible through its per-result error. The tool returned success unconditionally, which meant an offboarding agent would carry on believing a Chromebook had been disabled or deprovisioned when it had not. The transform now partitions the results and fails the tool when any device errored, naming each failing device and Google's reason. Both sides of the split are also exposed as succeededDeviceIds and failedDeviceIds so a partial failure can be retried for just the remainder instead of re-running the whole batch — which matters for DEPROVISION, where a repeat on an already-deprovisioned device is not harmless.
1 parent 682f043 commit 98c7ba7

4 files changed

Lines changed: 61 additions & 3 deletions

File tree

apps/docs/content/docs/en/integrations/google_workspace_admin.mdx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -790,6 +790,8 @@ Deprovision, disable, or re-enable up to 50 ChromeOS devices at once. Deprovisio
790790
|`deviceId` | string | Unique ID of the ChromeOS device |
791791
|`response` | json | Present when the device changed status successfully |
792792
|`error` | json | Present when the device failed to change status, with code, message, and details |
793+
| `succeededDeviceIds` | array | IDs of the devices that did change status, so a partial failure can be retried for the rest |
794+
| `failedDeviceIds` | array | IDs of the devices that did not change status |
793795

794796
### Google Workspace Admin List Activities
795797

apps/sim/blocks/blocks/google_workspace_admin.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1283,6 +1283,14 @@ Return ONLY the query string - no explanations, no quotes, no extra text.`,
12831283
type: 'json',
12841284
description: 'Per-device status change results ([{deviceId, response, error}])',
12851285
},
1286+
succeededDeviceIds: {
1287+
type: 'json',
1288+
description: 'IDs of the ChromeOS devices that did change status ([deviceId])',
1289+
},
1290+
failedDeviceIds: {
1291+
type: 'json',
1292+
description: 'IDs of the ChromeOS devices that did not change status ([deviceId])',
1293+
},
12861294
activities: { type: 'json', description: 'Array of audit Activity resources' },
12871295
usageReports: { type: 'json', description: 'Array of UsageReport resources' },
12881296
warnings: { type: 'json', description: 'Warnings returned alongside a usage report' },

apps/sim/tools/generated/tool-outputs.ts

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

apps/sim/tools/google_workspace_admin/batch_change_chromeos_device_status.ts

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,19 @@ import {
1111
} from '@/tools/google_workspace_admin/utils'
1212
import type { ToolConfig } from '@/tools/types'
1313

14+
/**
15+
* A per-device outcome. The Admin SDK returns HTTP 200 for the batch as a whole
16+
* and reports each device individually, so a device that stayed enabled is only
17+
* visible through its `error`.
18+
*/
19+
interface ChangeChromeOsDeviceStatusResult {
20+
deviceId?: string
21+
response?: unknown
22+
error?: { code?: number; message?: string; details?: unknown[] }
23+
}
24+
1425
interface BatchChangeChromeOsDeviceStatusApiResponse {
15-
changeChromeOsDeviceStatusResults?: unknown[]
26+
changeChromeOsDeviceStatusResults?: ChangeChromeOsDeviceStatusResult[]
1627
}
1728

1829
/**
@@ -101,10 +112,36 @@ export const batchChangeChromeOsDeviceStatusTool: ToolConfig<
101112
response,
102113
'Failed to change ChromeOS device status'
103114
)
115+
const results = data.changeChromeOsDeviceStatusResults ?? []
116+
const failed = results.filter((result) => result.error !== undefined)
117+
const succeededDeviceIds = results
118+
.filter((result) => result.error === undefined)
119+
.map((result) => result.deviceId ?? '')
120+
.filter((deviceId) => deviceId.length > 0)
121+
122+
if (failed.length > 0) {
123+
return {
124+
success: false,
125+
error: `${failed.length} of ${results.length} ChromeOS devices failed to change status: ${failed
126+
.map(
127+
(result) =>
128+
`${result.deviceId ?? 'unknown device'} (${result.error?.message ?? 'no reason given'})`
129+
)
130+
.join('; ')}`,
131+
output: {
132+
changeChromeOsDeviceStatusResults: results,
133+
succeededDeviceIds,
134+
failedDeviceIds: failed.map((result) => result.deviceId ?? '').filter(Boolean),
135+
},
136+
}
137+
}
138+
104139
return {
105140
success: true,
106141
output: {
107-
changeChromeOsDeviceStatusResults: data.changeChromeOsDeviceStatusResults ?? [],
142+
changeChromeOsDeviceStatusResults: results,
143+
succeededDeviceIds,
144+
failedDeviceIds: [],
108145
},
109146
}
110147
},
@@ -132,5 +169,16 @@ export const batchChangeChromeOsDeviceStatusTool: ToolConfig<
132169
},
133170
},
134171
},
172+
succeededDeviceIds: {
173+
type: 'array',
174+
description:
175+
'IDs of the devices that did change status, so a partial failure can be retried for the rest',
176+
items: { type: 'string' },
177+
},
178+
failedDeviceIds: {
179+
type: 'array',
180+
description: 'IDs of the devices that did not change status',
181+
items: { type: 'string' },
182+
},
135183
},
136184
}

0 commit comments

Comments
 (0)