/** * c_entra_get_group_memberships * * Diagnostic cloud-proxy tool: lists the entra security and microsoft 365 groups a user directly belongs to. returns group id and display name via the cloud gateway. * * Wire contract * ------------- * GET ${CLOUD_GATEWAY_URL}/entra/users/{upn}/groups * X-Idemeum-Eoc-Api-Key: ${CLOUD_GATEWAY_API_KEY} */import { z } from "zod";import { cloudGatewayCall, type CloudGatewayResult } from "./_shared/cloudGateway";// -- Meta ---------------------------------------------------------------------export const meta = { name: "c_entra_get_group_memberships", description: "Lists the Entra security and Microsoft 365 groups a user directly belongs to. Returns group ID and display name via the cloud gateway.", riskLevel: "low", destructive: false, requiresConsent: false, supportsDryRun: false, auditRequired: true, affectedScope: ["network"], requiresVerifiedIdentity: true, sensitiveParams: [], outputKeys: [ "status", "message", "groups", "httpStatus", "failureReason", ], schema: {},} as const;// -- Types --------------------------------------------------------------------interface GroupsEntry { id: string; displayName: string;}interface EntraGetGroupMembershipsData { groups: GroupsEntry[];}export interface EntraGetGroupMembershipsResult { status: "ok" | "failed" | "not-configured"; message: string; groups?: GroupsEntry[]; httpStatus?: number; failureReason?: CloudGatewayResult["failureReason"];}// -- Implementation -----------------------------------------------------------export async function run(_args: Record<string, never>, ctx?: { verifiedUpn?: string; userSessionHandle?: string }): Promise<EntraGetGroupMembershipsResult> { // Subject comes from the verified session, never from args — see // ToolRunContext.verifiedUpn in electron/agent/guards/execution.ts. if (!ctx?.verifiedUpn) { return { status: "failed", message: "No verified identity for this run.", } as never; } const upn = encodeURIComponent(ctx.verifiedUpn); const r = await cloudGatewayCall<EntraGetGroupMembershipsData>({ path: `/entra/users/${upn}/groups`, userSessionHandle: ctx?.userSessionHandle, }); if (r.status !== "ok") { return { status: r.status, message: r.message, httpStatus: r.httpStatus, failureReason: r.failureReason, }; } const d = r.data!; return { status: "ok", message: (Array.isArray(d.groups) ? d.groups.length : 0) + " group(s) found.", groups: d.groups, };}