Code

/**
 * mcp/skills/resyncIdpAgent.ts — resync_idp_agent
 *
 * Triggers a re-sync of the installed IDP companion agent after a
 * password reset.  The goal is to flush any cached session/token state
 * so the user's next sign-in uses the new password.
 *
 * Platform strategy
 * -----------------
 * Okta Verify:
 *   darwin  killall "Okta Verify" ; open -a "Okta Verify"
 *   win32   net stop / net start the Okta Verify service if present;
 *           otherwise taskkill + Start-Process the user-mode binary.
 *
 * Jamf Connect (darwin only):
 *   launchctl kickstart -k system/com.jamf.connect (requires sudo)
 *
 * Entra (Microsoft Intune):
 *   darwin  killall "Company Portal" ; open -a "Company Portal"
 *   win32   dsregcmd /refreshprt  (safe, read-mostly)
 *
 * Each action is best-effort — failures report a clear error message and
 * the skill continues with the remaining steps.
 */
 
import { z } from "zod";
import { isDarwin, isWin32, execAsync } from "./_shared/platform";
import { idpDisplayName, type Idp } from "./_shared/idp";
 
// -- Meta ---------------------------------------------------------------------
 
export const meta = {
  name: "resync_idp_agent",
  description:
    "Restarts or refreshes the installed IDP companion agent (Okta Verify, " +
    "Jamf Connect, Microsoft Entra / Intune) so cached session tokens are " +
    "flushed and the next sign-in uses the new password. Best-effort — " +
    "surfaces a clear error if the agent is not installed or the OS refuses.",
  riskLevel:       "medium",
  destructive:     false,
  requiresConsent: true,
  supportsDryRun:  true,
  affectedScope:   ["user"],
  auditRequired:   true,
  schema: {
    idp: z
      .enum(["okta", "entra", "google", "unknown"])
      .describe("IDP identifier from detect_identity_provider."),
    dryRun: z
      .boolean()
      .optional()
      .describe("When true, report the exact commands that would run without executing."),
  },
} as const;
 
// -- Types --------------------------------------------------------------------
 
export interface ResyncResult {
  idp:       Idp;
  idpLabel:  string;
  platform:  "darwin" | "win32" | "other";
  dryRun:    boolean;
  /** Each attempted action's outcome. */
  actions:   Array<{
    description: string;
    command:     string;
    executed:    boolean;
    success?:    boolean;
    error?:      string;
  }>;
  skipped?:  boolean;
  message:   string;
}
 
// -- Implementation -----------------------------------------------------------
 
async function runCommand(description: string, command: string, dryRun: boolean): Promise<{
  description: string; command: string; executed: boolean; success?: boolean; error?: string;
}> {
  if (dryRun) return { description, command, executed: false };
  try {
    await execAsync(command, { maxBuffer: 1 * 1024 * 1024, timeout: 10_000 });
    return { description, command, executed: true, success: true };
  } catch (err) {
    return {
      description, command, executed: true, success: false,
      error: (err as Error).message,
    };
  }
}
 
async function resyncOktaDarwin(dryRun: boolean): Promise<ResyncResult["actions"]> {
  return [
    await runCommand(
      "Quit Okta Verify",
      `killall "Okta Verify" 2>/dev/null || true`,
      dryRun,
    ),
    await runCommand(
      "Relaunch Okta Verify",
      `open -a "Okta Verify" 2>/dev/null || true`,
      dryRun,
    ),
  ];
}
 
async function resyncOktaWin32(dryRun: boolean): Promise<ResyncResult["actions"]> {
  return [
    await runCommand(
      "Stop Okta Verify service (if installed)",
      `net stop "Okta Verify Service" 2>nul & exit 0`,
      dryRun,
    ),
    await runCommand(
      "Start Okta Verify service (if installed)",
      `net start "Okta Verify Service" 2>nul & exit 0`,
      dryRun,
    ),
  ];
}
 
async function resyncEntraDarwin(dryRun: boolean): Promise<ResyncResult["actions"]> {
  return [
    await runCommand(
      "Quit Microsoft Company Portal",
      `killall "Company Portal" 2>/dev/null || true`,
      dryRun,
    ),
    await runCommand(
      "Relaunch Microsoft Company Portal",
      `open -a "Company Portal" 2>/dev/null || true`,
      dryRun,
    ),
  ];
}
 
async function resyncEntraWin32(dryRun: boolean): Promise<ResyncResult["actions"]> {
  return [
    await runCommand(
      "Refresh Entra PRT (primary refresh token)",
      `dsregcmd /refreshprt`,
      dryRun,
    ),
  ];
}
 
// Jamf Connect — present on some Okta-managed macOS fleets; we invoke it
// automatically when present.  Idempotent + safe to run even when Jamf
// Connect isn't configured: launchctl kickstart will no-op on a missing
// service with a clean non-zero exit that we swallow.
async function resyncJamfConnectDarwin(dryRun: boolean): Promise<ResyncResult["actions"]> {
  return [
    await runCommand(
      "Restart Jamf Connect (if installed)",
      `launchctl kickstart -k system/com.jamf.connect 2>/dev/null || true`,
      dryRun,
    ),
  ];
}
 
// Exported for unit tests.
export const __testing = {
  resyncOktaDarwin, resyncOktaWin32,
  resyncEntraDarwin, resyncEntraWin32,
  resyncJamfConnectDarwin,
};
 
// -- Exported run function ----------------------------------------------------
 
export async function run({
  idp,
  dryRun = false,
}: {
  idp:     Idp;
  dryRun?: boolean;
}): Promise<ResyncResult> {
  const platform: "darwin" | "win32" | "other" =
    isDarwin() ? "darwin" : isWin32() ? "win32" : "other";
  const idpLabel = idpDisplayName(idp);
 
  if (idp === "unknown" || idp === "google") {
    return {
      idp, idpLabel, platform, dryRun, actions: [], skipped: true,
      message:
        idp === "unknown"
          ? "IDP is unknown — no agent to re-sync."
          : "Google Workspace has no endpoint companion agent to re-sync.",
    };
  }
 
  const actions: ResyncResult["actions"] = [];
 
  if (idp === "okta") {
    if (platform === "darwin") {
      actions.push(...(await resyncOktaDarwin(dryRun)));
      actions.push(...(await resyncJamfConnectDarwin(dryRun)));
    } else if (platform === "win32") {
      actions.push(...(await resyncOktaWin32(dryRun)));
    }
  } else if (idp === "entra") {
    if (platform === "darwin") {
      actions.push(...(await resyncEntraDarwin(dryRun)));
    } else if (platform === "win32") {
      actions.push(...(await resyncEntraWin32(dryRun)));
    }
  }
 
  if (actions.length === 0) {
    return {
      idp, idpLabel, platform, dryRun, actions, skipped: true,
      message: `No resync commands available for ${idpLabel} on ${platform}.`,
    };
  }
 
  const successes = actions.filter((a) => a.success).length;
  const failures  = actions.filter((a) => a.executed && a.success === false).length;
 
  return {
    idp, idpLabel, platform, dryRun, actions,
    message: dryRun
      ? `Would run ${actions.length} resync command(s) for ${idpLabel}.`
      : `Ran ${actions.length} resync command(s) for ${idpLabel}: ` +
        `${successes} succeeded, ${failures} failed.`,
  };
}
 
// -- CLI smoke test -----------------------------------------------------------
 
if (false) {
  run({ idp: "okta", dryRun: true })
    .then((r) => console.log(JSON.stringify(r, null, 2)))
    .catch((err: Error) => { console.error(err.message); process.exit(1); });
}