Files
sim/apps
Waleed d64ad856f1 improvement(microsoft-ad): add pagination support and fill BlockMeta gaps (#5442)
* improvement(microsoft-ad): add pagination support and fill BlockMeta gaps

Full validate-integration pass against live Microsoft Graph API docs. No
critical bugs found (endpoints, methods, params, and OAuth scopes were
already correct). Fixed the real gaps:

- List Users/Groups/Group Members had no way to page past the default
  Graph page size (100, max 999 via $top), which silently truncated
  results for the block's own audit/sweep templates. Added a nextLink
  input/output following the same convention as microsoft_dataverse.
- Create Group's visibility dropdown was missing HiddenMembership, a
  valid Microsoft 365-only value that can only be set at creation time.
- Rounded out BlockMeta skills (3 -> 5) with two more real, tool-grounded
  use cases: directory search and ad hoc group membership changes.

* fix(microsoft-ad): correct $search syntax and create-user response fields

Independent 4-agent re-audit against live Graph docs surfaced two real bugs
predating this PR:

- list_users/list_groups sent $search="<term>" with no property prefix.
  Graph requires the "property:value" form for directory-object search
  (e.g. "displayName:term" OR "mail:term") and 400s on a bare string.
- create_user's POST had no $select, so Graph's default create response
  omits department/accountEnabled even when submitted, making
  transformResponse report them back as null. Added the same $select used
  by list/get so the response reflects what was actually set.

Also tightened create_group's visibility description: only HiddenMembership
is create-only: Private/Public can still be changed after creation via
Update Group.

* fix(microsoft-ad): validate nextLink origin, allow nextLink-only pagination

Greptile and Cursor both flagged the same real issue: nextLink was passed
straight to fetch() as the request URL with no origin check, while the
OAuth bearer token was always attached. A crafted or prompt-injected
nextLink pointing outside graph.microsoft.com would exfiltrate the token.

Fix: reuse the existing assertGraphNextPageUrl/getGraphNextPageUrl helpers
from tools/sharepoint/utils (already the shared pattern for SharePoint,
OneDrive, Teams, Planner, Outlook, Excel Graph pagination) instead of a
bespoke unvalidated pass-through.

Cursor also caught that list_group_members required groupId even when
only nextLink was supplied for a later page. Relaxed groupId to optional
at the tool level, matching how sharepoint_get_list treats its analogous
listId param — the URL builder still throws a clear error if neither
groupId nor nextLink is given.

* fix(microsoft-ad): allow $search+$filter combo, escape backslashes, fix pagination UX

Second independent 4-agent re-audit of the final state (post security fix)
surfaced 3 more real issues:

- list_users/list_groups threw an error whenever $search and $filter were
  both supplied, claiming Graph doesn't support combining them. It does
  (AND semantics, documented) — the check was blocking valid, documented
  usage for no reason. Removed it.
- The $search term escaping only handled embedded double quotes, not
  backslashes, which Graph's own escaping rule also requires. Fixed the
  replace order (backslashes first, then quotes).
- list_group_members's Group ID field was still hard-required in the
  block UI for every operation including list_group_members, undermining
  the nextLink-only pagination path added earlier (the tool itself no
  longer requires it). Dropped list_group_members from the UI-required
  list, matching the tool's own conditional requirement — the runtime
  "Group ID is required" check still catches a genuinely empty call.
2026-07-06 15:48:43 -07:00
..