sync_system_time
sync_system_time
Forces an immediate NTP clock resync on the endpoint. Use ONLY after check_ntp_status reports significant drift. Requires admin privileges, supplied by the privileged helper daemon for non-admin users. Large time jumps can break in-flight TLS sessions and trigger endpoint security software alerts — always run dry-run first so the user can see the command.
Metadata
Name
sync_system_time
Updated
2 months ago
Source
Risk
Medium
Requires consent
true
Affected scope
system
Code
/**
* mcp/skills/syncSystemTime.ts — sync_system_time
*
* Forces an immediate NTP resync. The identity-auth-repair skill calls
* this after check_ntp_status reports significant drift.
*
* Privilege model
* ---------------
* NTP clock writes require admin / LocalSystem privilege. The agent runs
* as the standard user; G4 routes this tool through the privileged helper
* daemon (Workstream D — sync_system_time handler) so non-admin users
* complete the resync end-to-end without an interactive sudo prompt.
* When the helper is unavailable (HELPER_DAEMON_ENABLED=false / not
* installed / unreachable), the call denies with helper-error /
* helper-unavailable / scope-boundary; the agent surfaces the dry-run
* preview (which formats `formatSyncError` guidance) so the user can run
* the command manually as a last resort.
*
* Platform strategy
* -----------------
* darwin helper runs `sntp -sS <server>` (default `time.apple.com`)
* win32 helper runs `w32tm /resync /force` (server param ignored —
* W32Time reads from its configured peer)
*
* Large time jumps can trigger endpoint security software alerts and
* break TLS sessions mid-flight — hence requiresConsent + supportsDryRun.
* Dry-run reports the exact command the helper would run.
*/
import { z } from "zod";
import { isDarwin, isWin32 } from "./_shared/platform";
// -- Meta ---------------------------------------------------------------------
export const meta = {
name: "sync_system_time",
description:
"Forces an immediate NTP clock resync on the endpoint. Use ONLY after " +
"check_ntp_status reports significant drift. Requires admin privileges, " +
"supplied by the privileged helper daemon for non-admin users. Large " +
"time jumps can break in-flight TLS sessions and trigger endpoint " +
"security software alerts — always run dry-run first so the user can " +
"see the command.",
riskLevel: "medium",
destructive: false,
requiresConsent: true,
supportsDryRun: true,
affectedScope: ["system"],
auditRequired: true,
schema: {
server: z
.string()
.optional()
.describe(
"Reference NTP server. Defaults to 'time.apple.com' on macOS. " +
"Ignored on Windows — W32Time reads from its configured peer."
),
dryRun: z
.boolean()
.optional()
.describe("When true, report the command that would run without executing."),
},
} as const;
// -- Types --------------------------------------------------------------------
export interface SyncTimeResult {
platform: "darwin" | "win32" | "other";
server: string;
command: string;
dryRun: boolean;
success: boolean;
message: string;
}
// -- Default server -----------------------------------------------------------
const DEFAULT_SERVER = "time.apple.com";
// -- Dry-run preview (platform-aware, local) ---------------------------------
function plannedCommand(platform: "darwin" | "win32" | "other", server: string): string {
if (platform === "darwin") return `sntp -sS ${shellQuote(server)}`;
if (platform === "win32") return "w32tm /resync /force";
return "(unsupported)";
}
function previewDarwin(server: string): SyncTimeResult {
const command = plannedCommand("darwin", server);
return {
platform: "darwin",
server,
command,
dryRun: true,
success: true,
message: `Would run \\`${command}\"` via the privileged helper. No changes yet.`,
};
}
function previewWin32(server: string): SyncTimeResult {
const command = plannedCommand("win32", server);
return {
platform: "win32",
server,
command,
dryRun: true,
success: true,
message: `Would run \\`${command}\"` via the privileged helper. No changes yet.`,
};
}
function previewUnsupported(server: string): SyncTimeResult {
return {
platform: "other",
server,
command: "(unsupported)",
dryRun: true,
success: false,
message: "Unsupported platform — cannot sync system time.",
};
}
function shellQuote(s: string): string {
return `\'${s.replace(/'/g, `\'\'`)}\'`;
}
/**
* Maps a raw error message to a user-friendly guidance message per
* platform. Used for the dry-run preview's manual-fallback hint when
* the helper is unavailable — the user can run the underlying command
* themselves with elevated privileges as a last resort.
*
* Exported for unit tests.
*/
export function formatSyncError(platform: "darwin" | "win32", msg: string, command: string): string {
if (platform === "darwin") {
return /sudo/i.test(msg)
? `sudo authentication required. Ask the user to run \\`${command}\\` manually, or re-run this with elevated privileges.`
: `sntp failed: ${msg}`;
}
if (/access is denied/i.test(msg) || /^5:/.test(msg)) {
return `Admin rights required. Open an elevated Command Prompt and run \\`${command}\\`.`;
}
return `w32tm /resync /force failed: ${msg}`;
}
// -- Exported run function ----------------------------------------------------
export async function run({
server,
dryRun = false,
}: {
server?: string;
dryRun?: boolean;
} = {}): Promise<SyncTimeResult> {
const platform: "darwin" | "win32" | "other" =
isDarwin() ? "darwin" : isWin32() ? "win32" : "other";
const resolvedServer = server ?? DEFAULT_SERVER;
if (dryRun) {
// Dry-run: rendered locally so the consent card has something to
// display. This is side-effect free and returns the exact command
// the helper would execute on confirmation.
if (platform === "darwin") return previewDarwin(resolvedServer);
if (platform === "win32") return previewWin32(resolvedServer);
return previewUnsupported(resolvedServer);
}
// Real-run: G4's scope-boundary check routes this op through the helper
// daemon automatically because affectedScope: ["system"] + the helper
// allowlist contains "sync_system_time". The agent-side tool does NOT
// shell out to `sudo sntp` / `w32tm` directly — that would bypass the
// helper-routing pipeline, fail for non-admin users, and split the
// audit trail between agent-local and helper-side logs. Instead, we
// throw a sentinel error here that the G4 layer intercepts and replaces
// with the helper-routed call.
//
// When the agent runtime invokes this tool with dryRun=false, it does
// so through the G4 executeStep, which has already chosen "route via
// helper" for this tool. The helper returns { server, command,
// duration_ms }; the runtime maps that into the SyncTimeResult shape.
throw new Error(
"sync_system_time is helper-routed; the agent runtime should call the " +
"helper bridge directly rather than this tool's local run(). " +
"Reaching this code means the routing layer didn't intercept the call."
);
}
// -- CLI smoke test -----------------------------------------------------------
if (false) {
run({ dryRun: true })
.then((r) => console.log(JSON.stringify(r, null, 2)))
.catch((err: Error) => { console.error(err.message); process.exit(1); });
}