# Copyright 2025-present the Unsloth AI Inc. team. All rights reserved. """Pure resolver for `unsloth run --enable-tools/--disable-tools`. Kept as a standalone module so the truth table can be unit-tested without spinning up Typer or the studio venv. """ from typing import Callable, Optional import typer # Orange so the security warning stands out in a crowded terminal. _PROMPT_FG = (217, 119, 87) # Loopback aliases; any other bind address is treated as network-reachable. _LOOPBACK_HOSTS = frozenset({"127.0.0.1", "localhost", "::1"}) def is_external_host(host: str) -> bool: """True when `host` is reachable from beyond loopback.""" return host.lower() not in _LOOPBACK_HOSTS def _build_prompt_text(host: str) -> str: return typer.style( ( f"Tools include arbitrary code execution (Python, terminal). " f"You're binding to {host}, which is reachable from your network. " f"If your API key leaks, anyone with it can run code on this machine. " f"Do not share the API key. Continue?" ), fg = _PROMPT_FG, bold = True, ) def resolve_tool_policy( host: str, flag: Optional[bool], yes: bool, silent: bool, prompt: Callable[[str], bool] = typer.confirm, ) -> bool: """Return the resolved server-side tool policy. Args: host: The bind address. flag: Tri-state from `--enable-tools/--disable-tools` (None if neither passed). yes: True if `--yes/-y` was passed. silent: True if `--silent/-q` was passed. prompt: Confirmation callable (injected for testability). Raises: typer.Exit: when the operator declines the confirmation. """ is_external = is_external_host(host) default = not is_external # loopback defaults on, network defaults off resolved = default if flag is None else flag if is_external and resolved is True and not yes and not silent: if not prompt(_build_prompt_text(host)): raise typer.Exit(1) return resolved