// fail2ban's tools — reading and steering the live ban state. The jails themselves are declared // resources (module.json); these three touch what the running daemon holds: what is banned now, // and the manual ban/unban an operator reaches for. The daemon's state is fail2ban's own, so this // is the only way to see or change it — the mesh reconciles the config, not the bans. import { registerModuleTools, type ToolDefinition } from "@novox/mesh-sdk/tools"; import { Fail2banClient } from "../client.js"; export function getFail2banTools(fail2ban: Fail2banClient): ToolDefinition[] { return [ { name: "fail2ban_status", description: "fail2ban status on this node — the jails and their live bans. Omit `jail` for every jail, or name one for its detail.", input: { type: "object", properties: { jail: { type: "string", description: "A specific jail (e.g. sshd, recidive); omit for the overview of all jails.", }, }, }, run: async (args) => ({ status: await fail2ban.status(args.jail as string | undefined) }), }, { name: "fail2ban_ban", description: "Manually ban an IP address in a jail — a live change to the running daemon, not a mesh-managed file.", input: { type: "object", properties: { jail: { type: "string", description: "Jail name (e.g. sshd, recidive)." }, ip: { type: "string", description: "IP address to ban." }, }, required: ["jail", "ip"], }, run: async (args) => ({ result: await fail2ban.ban(args.jail as string, args.ip as string) }), }, { name: "fail2ban_unban", description: "Unban an IP address from one jail, or from every jail when `jail` is omitted.", input: { type: "object", properties: { ip: { type: "string", description: "IP address to unban." }, jail: { type: "string", description: "A specific jail; omit to unban from all jails." }, }, required: ["ip"], }, run: async (args) => ({ result: await fail2ban.unban(args.ip as string, args.jail as string | undefined) }), }, ]; } registerModuleTools("fail2ban", () => getFail2banTools(Fail2banClient.fromEnv()));