Code

/**
 * c_entra_reset_mfa
 *
 * Corrective cloud-proxy tool: resets all mfa registration methods for an entra user. the user will be prompted to re-enroll mfa on their next sign-in via the cloud gateway. supports dry-run to preview the operation without executing.
 *
 * Wire contract
 * -------------
 * POST ${CLOUD_GATEWAY_URL}/entra/users/{upn}/mfa/reset
 *   X-Idemeum-Eoc-Api-Key: ${CLOUD_GATEWAY_API_KEY}
 *   Body: {}
 */
 
import { z } from "zod";
import { cloudGatewayCall, type CloudGatewayResult } from "./_shared/cloudGateway";
 
// -- Meta ---------------------------------------------------------------------
 
export const meta = {
  name: "c_entra_reset_mfa",
  description:
    "Resets all MFA registration methods for an Entra user. The user will be prompted to re-enroll MFA on their next sign-in via the cloud gateway. Supports dry-run to preview the operation without executing.",
  riskLevel:       "high",
  destructive:     false,
  requiresConsent: true,
  supportsDryRun:  true,
  auditRequired:   true,
  affectedScope:   ["network"],
  requiresVerifiedIdentity: true,
  sensitiveParams: [],
  outputKeys: [
    "status",
    "message",
    "willPost",
    "endpoint",
    "httpStatus",
    "failureReason",
  ],
  schema: {
    dryRun: z
      .boolean()
      .nullable().optional()
      .describe("When true, returns the operation preview without executing."),
  },
} as const;
 
// -- Types --------------------------------------------------------------------
 
interface EntraResetMfaData {
  status:  "initiated" | "failed";
  message: string;
}
 
export interface EntraResetMfaResult {
  status:         "ok" | "failed" | "not-configured";
  message:        string;
  willPost?:      boolean;
  endpoint?:      string;
  httpStatus?:    number;
  failureReason?: CloudGatewayResult["failureReason"];
}
 
// -- Implementation -----------------------------------------------------------
 
export async function run(args: {
  dryRun?: boolean;
}, ctx?: { verifiedUpn?: string; userSessionHandle?: string }): Promise<EntraResetMfaResult> {
  const baseUrl = process.env["CLOUD_GATEWAY_URL"];
  // 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 path = `/entra/users/${upn}/mfa/reset`;
 
  if (args.dryRun) {
    return {
      status:   "ok",
      message:  `Would POST reset mfa for ${ctx?.verifiedUpn ?? "the signed-in user"}.`,
      willPost: true,
      endpoint: baseUrl ? baseUrl.replace(/\/$/, "") + path : "(CLOUD_GATEWAY_URL not set)",
    };
  }
 
  const r = await cloudGatewayCall<EntraResetMfaData>({
    method: "POST",
    path,
    userSessionHandle: ctx?.userSessionHandle,
  });
 
  if (r.status !== "ok") {
    return {
      status:        r.status === "not-configured" ? "not-configured" : "failed",
      message:       r.message,
      httpStatus:    r.httpStatus,
      failureReason: r.failureReason,
    };
  }
 
  const d = r.data!;
  return {
    status:  d.status === "initiated" ? "ok" : "failed",
    message: d.message,
  };
}