/**
* c_entra_get_licenses
*
* Diagnostic cloud-proxy tool: lists the microsoft 365 licence skus currently assigned to a user, with sku id and part number via the cloud gateway.
*
* Wire contract
* -------------
* GET ${CLOUD_GATEWAY_URL}/entra/users/{upn}/licenses
* 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_licenses",
description:
"Lists the Microsoft 365 licence SKUs currently assigned to a user, with SKU ID and part number via the cloud gateway.",
riskLevel: "low",
destructive: false,
requiresConsent: false,
supportsDryRun: false,
auditRequired: true,
affectedScope: ["network"],
requiresVerifiedIdentity: true,
sensitiveParams: [],
outputKeys: [
"status",
"message",
"licenses",
"httpStatus",
"failureReason",
],
schema: {},
} as const;
// -- Types --------------------------------------------------------------------
interface LicensesEntry {
skuId: string;
skuPartNumber: string;
}
interface EntraGetLicensesData {
licenses: LicensesEntry[];
}
export interface EntraGetLicensesResult {
status: "ok" | "failed" | "not-configured";
message: string;
licenses?: LicensesEntry[];
httpStatus?: number;
failureReason?: CloudGatewayResult["failureReason"];
}
// -- Implementation -----------------------------------------------------------
export async function run(_args: Record<string, never>, ctx?: { verifiedUpn?: string; userSessionHandle?: string }): Promise<EntraGetLicensesResult> {
// 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<EntraGetLicensesData>({
path: `/entra/users/${upn}/licenses`,
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.licenses) ? d.licenses.length : 0) + " licence(s) assigned.",
licenses: d.licenses,
};
}