Skip to content

Commit 5a3568a

Browse files
committed
fix(microsoft_ad): clear the MFA flag and let paged user operations continue without a User ID
The set_password MFA dropdown only wrote its key when non-empty, so the "No Change" empty string survived `{ ...inputs, ...transformedParams }` and reached Graph in place of a boolean. Assign it explicitly, including as `undefined`, the same way `filter` and `search` are handled. `list_user_app_role_assignments` and `list_user_devices` page by `@odata.nextLink`, and both tools already treat `userId` as optional once a continuation URL is supplied. Drop them from the required set when Next Page is filled in so pagination-only runs pass block validation. Also note on the reset_password output that a generated password reaches workflow outputs, run history, and the model, matching how other tools that return secrets document exposure.
1 parent 5c2371c commit 5a3568a

4 files changed

Lines changed: 26 additions & 8 deletions

File tree

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -449,7 +449,7 @@ Reset another user's password through their password authentication method. Leav
449449
| --------- | ---- | ----------- |
450450
| `accepted` | boolean | Whether Microsoft Graph accepted the password reset operation |
451451
| `userId` | string | ID of the user whose password was reset |
452-
| `newPassword` | string | The system-generated password, returned only when no new password was supplied in the request |
452+
| `newPassword` | string | The system-generated password, returned only when no new password was supplied in the request. Like every tool output it appears in workflow outputs and run history, and is sent to the model when an agent calls this tool, so prefer supplying your own password when the value must not leave the workflow. |
453453
| `operationLocation` | string | URL to poll for the status of the long-running password reset operation |
454454

455455
### List Microsoft Entra ID Authentication Methods

apps/sim/blocks/blocks/microsoft_ad.ts

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,18 @@ const USER_ID_OPERATIONS = [
2121
'list_user_devices',
2222
]
2323

24+
/**
25+
* Per-user operations that page through an `@odata.nextLink`. The continuation URL already
26+
* addresses the user, so these are the only per-user operations that can run without a User ID,
27+
* and only when continuing from a previous page.
28+
*/
29+
const PAGED_USER_ID_OPERATIONS = ['list_user_app_role_assignments', 'list_user_devices']
30+
31+
/** Per-user operations that always require a User ID, whichever page is being fetched. */
32+
const ALWAYS_USER_ID_OPERATIONS = USER_ID_OPERATIONS.filter(
33+
(operation) => !PAGED_USER_ID_OPERATIONS.includes(operation)
34+
)
35+
2436
/** Collection operations that accept a page size and an @odata.nextLink continuation URL. */
2537
const PAGED_OPERATIONS = [
2638
'list_users',
@@ -55,7 +67,10 @@ const SHARED_FILTER_OPERATIONS = ['list_users', 'list_groups']
5567
*
5668
* The mapper must write `filter` and `search` on every operation, including as `undefined`. The
5769
* executor merges `{ ...inputs, ...transformedParams }`, so a key that is merely omitted here
58-
* leaves the stale serialized value in place rather than clearing it.
70+
* leaves the stale serialized value in place rather than clearing it. The same applies to every
71+
* optional field the mapper coerces out of a subBlock string, such as
72+
* `forceChangePasswordNextSignInWithMfa`: omitting the key on "No Change" would forward the raw
73+
* empty string to Graph in place of a boolean.
5974
*/
6075
const FILTER_FIELD_BY_OPERATION: Record<string, string> = {
6176
list_users: 'filter',
@@ -268,7 +283,10 @@ export const MicrosoftAdBlock: BlockConfig<MicrosoftAdResponse> = {
268283
type: 'short-input',
269284
placeholder: 'User ID or user principal name (e.g., user@example.com)',
270285
condition: { field: 'operation', value: USER_ID_OPERATIONS },
271-
required: { field: 'operation', value: USER_ID_OPERATIONS },
286+
required: (values) =>
287+
values?.nextLink
288+
? { field: 'operation', value: ALWAYS_USER_ID_OPERATIONS }
289+
: { field: 'operation', value: USER_ID_OPERATIONS },
272290
},
273291
// Create user fields
274292
{
@@ -797,9 +815,9 @@ export const MicrosoftAdBlock: BlockConfig<MicrosoftAdResponse> = {
797815
result.search = values[SEARCH_FIELD_BY_OPERATION[params.operation]] || undefined
798816
if (params.operation === 'set_password') {
799817
result.forceChangePasswordNextSignIn = params.forceChangePasswordNextSignIn !== 'false'
800-
if (params.forceChangePasswordNextSignInWithMfa)
801-
result.forceChangePasswordNextSignInWithMfa =
802-
params.forceChangePasswordNextSignInWithMfa === 'true'
818+
result.forceChangePasswordNextSignInWithMfa = params.forceChangePasswordNextSignInWithMfa
819+
? params.forceChangePasswordNextSignInWithMfa === 'true'
820+
: undefined
803821
}
804822
if (params.operation === 'update_user') {
805823
if (params.accountEnabled) result.accountEnabled = params.accountEnabled === 'true'

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

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

apps/sim/tools/microsoft_ad/reset_password.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ export const resetPasswordTool: ToolConfig<
9393
newPassword: {
9494
type: 'string',
9595
description:
96-
'The system-generated password, returned only when no new password was supplied in the request',
96+
'The system-generated password, returned only when no new password was supplied in the request. Like every tool output it appears in workflow outputs and run history, and is sent to the model when an agent calls this tool, so prefer supplying your own password when the value must not leave the workflow.',
9797
optional: true,
9898
},
9999
operationLocation: {

0 commit comments

Comments
 (0)