feat(platform): add Directory service for principal lookups - #665
feat(platform): add Directory service for principal lookups#665Sarath1018 wants to merge 1 commit into
Conversation
|
| * '<organizationId>' | ||
| * ); | ||
| * const isAdmin = memberships.length > 0; | ||
| * ``` |
There was a problem hiding this comment.
The getGroupMembership example uses directory without showing where it comes from — a user copying this block can't run it. search() correctly opens with full import + setup boilerplate; this one should too.
| * ``` | |
| * ```typescript | |
| * import { UiPath } from '@uipath/uipath-typescript/core'; | |
| * import { Directory } from '@uipath/uipath-typescript/platform'; | |
| * | |
| * const sdk = new UiPath(config); | |
| * await sdk.initialize(); | |
| * | |
| * const directory = new Directory(sdk); | |
| * const memberships = await directory.getGroupMembership( | |
| * '<userId>', | |
| * ['<adminGroupId>'], | |
| * '<organizationId>' | |
| * ); | |
| * const isAdmin = memberships.length > 0; | |
| * ``` |
|
|
||
| it('should return only the subset of groups the user belongs to', async () => { | ||
| const allGroups = await groups.getAll(organizationId); | ||
| const everyone = allGroups.find((g) => g.name === 'Everyone')!; |
There was a problem hiding this comment.
Non-null assertion here produces a cryptic TypeError: Cannot read properties of undefined (reading 'id') if the Everyone group doesn't exist. Per integration test convention, preconditions must use an explicit throw new Error(...).
| const everyone = allGroups.find((g) => g.name === 'Everyone')!; | |
| const everyone = allGroups.find((g) => g.name === 'Everyone'); | |
| if (!everyone) throw new Error('Expected an "Everyone" group in the organization — check test environment setup'); |
Review findingsTwo issues found, both actionable: 1. 2. Unguarded non-null assertion in integration test (line 114, |
9c25868 to
e954823
Compare
Adds PlatformDirectoryService (exported as Directory) to the /platform
subpath — the read-only lookup layer over an organization's principals:
- search(organizationId, options?) — find users, groups, and
applications by name prefix, entity type, and source
- getGroupMembership(userId, groupIds, organizationId) — returns the
subset of the given groups the user belongs to; the membership check
behind RBAC gating ("is this user in the Administrators group?")
Transforms: identifier→id and identityName→name renames, redundant
objectType dropped, numeric entity-type codes mapped to enums (live
API sends codes despite the spec declaring strings). Read-only service
— no bound methods, per convention.
Also hardens the Users integration suite against parallel-file races:
sibling suites mutate the shared test user's group memberships, so the
replace-semantics assertion now checks membership survival across the
update call instead of exact snapshot equality.
Verified against the live API: 2403 unit tests passing, all four
platform integration suites green in a parallel run (31/31).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
e954823 to
cf87e11
Compare
|
✅ No issues found. Checked for bugs and CLAUDE.md compliance. |
Summary
PR 3/4 in the platform RBAC stack (Users → Groups → Directory → Roles). Stacked on #664 — merge order: #663, #664, then this; the diff here is Directory-only.
Adds
PlatformDirectoryService(exported asDirectory) to the/platformsubpath — the read-only lookup layer over an organization's principals.search(organizationId, options?)GET /identity_/api/Directory/Search/{org}startsWith,entityType(user/group/application),sources(local/directory users/groups, robot accounts, applications)getGroupMembership(userId, groupIds, organizationId)POST /identity_/api/Directory/GroupMembership/{org}groupIdsthe user belongs to — the RBAC membership check ("is this user an admin?")Design decisions (validated against the live API)
identifier→id,identityName→name(SDK-wide naming); redundantobjectTypediscriminator droppedtypearrives as0/1/2despite the spec's string enum — mapped toPlatformDirectoryEntityTypeidentityNamevsname) — typed independently per the wire-format-first conventionTesting
sources→sourceFilter, empty results, all validation branches)Docs
docs/oauth-scopes.md(PM.Directory.Read— directory has no parent/write scope),mkdocs.ymlnav. No pagination.md entry (plain arrays).Stack
mainfeat/platform-usersfeat/platform-groupsfeat/platform-directory🤖 Generated with Claude Code