Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 44 additions & 10 deletions unsloth_cli/commands/start.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,22 @@
# the wizard's global API-key/model prompts would block the launch and point the
# user at a different (global) provider than the one Unsloth just configured.
# Both installers expose a skip flag: `-SkipSetup` (PowerShell) and
# `--skip-setup` (POSIX; passed to the piped script via `bash -s --`).
# `--skip-setup` (POSIX; passed to the piped script via `bash -s --`). Pin both
# the fetched script and the repository checkout it performs to the same full
# commit so a later change to either upstream branch cannot silently replace
# code that Unsloth executes with the user's privileges.
_HERMES_INSTALL_COMMIT = "f1af945f6c576eccb126fa955edc9be258b33020"
_HERMES_INSTALL_BASE = (
"https://raw.githubusercontent.com/NousResearch/hermes-agent/"
f"{_HERMES_INSTALL_COMMIT}/scripts"
)
_HERMES_WINDOWS_INSTALL_HINT = (
"& ([scriptblock]::Create((irm https://hermes-agent.nousresearch.com/install.ps1))) -SkipSetup"
f"& ([scriptblock]::Create((irm {_HERMES_INSTALL_BASE}/install.ps1)))"
f" -SkipSetup -Commit {_HERMES_INSTALL_COMMIT}"
)
_HERMES_POSIX_INSTALL_HINT = (
"curl -fsSL https://raw.githubusercontent.com/NousResearch/hermes-agent"
"/main/scripts/install.sh | bash -s -- --skip-setup"
f"curl -fsSL {_HERMES_INSTALL_BASE}/install.sh | bash -s --"
f" --skip-setup --commit {_HERMES_INSTALL_COMMIT}"
)
# Hermes refuses to initialize when the model window is under 64,000 tokens; its
# error message points at the model.context_length / auxiliary.compression
Expand Down Expand Up @@ -1121,6 +1130,16 @@ def _install_source(install_hint: str) -> Optional[str]:
return match.group(0) if match else None


def _pinned_raw_github_commit(source: str) -> Optional[str]:
"""Return the immutable full commit in a raw GitHub URL, if present."""
match = re.match(
r"^https://raw\.githubusercontent\.com/[^/]+/[^/]+/([0-9a-f]{40})/",
source,
flags = re.IGNORECASE,
)
return match.group(1).lower() if match else None


def _install_agent(name: str, install_hint: str) -> Optional[str]:
# Missing agent under --launch: offer to run its documented install command, then
# re-resolve it on PATH. Consent-based (we never auto-run a remote install script
Expand All @@ -1134,12 +1153,27 @@ def _install_agent(name: str, install_hint: str) -> Optional[str]:
# and nothing checks a signature or hash on the fetched content. Naming the source
# turns a blind "yes" into informed consent.
source = _install_source(install_hint)
warning = (
f"This will download and RUN a script from {source} with your privileges"
if source
else f"This will RUN `{install_hint}` with your privileges"
)
typer.secho(f"{warning}; there is no signature or hash check.", fg = "yellow", err = True)
if source:
pinned_commit = _pinned_raw_github_commit(source)
if pinned_commit:
warning = (
"Security warning: This will download and execute a third-party script "
f"from {source} with your privileges. Unsloth pins this content to "
f"immutable upstream commit {pinned_commit}, but does not independently "
"verify or sandbox it. Continue only if you trust this source and commit."
)
else:
warning = (
"Security warning: This will download and execute an unverified third-party "
f"script from {source} with your privileges. Unsloth does not pin or verify "
"the downloaded content. Continue only if you trust this source."
)
else:
warning = (
f"This will RUN `{install_hint}` with your privileges; "
"there is no signature or hash check."
)
typer.secho(warning, fg = "yellow", err = True)
if not typer.confirm(f"Install `{name}` now with `{install_hint}`?", default = False):
return None
# Run each hint through the shell it is written for: PowerShell (irm | iex, or npm)
Expand Down
38 changes: 31 additions & 7 deletions unsloth_cli/tests/test_start.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import json
import os
import re
import shlex
import sys
import urllib.error
Expand Down Expand Up @@ -128,7 +129,7 @@ def test_install_agent_uses_powershell_on_windows(monkeypatch):
assert ran == [["powershell", "-NoProfile", "-Command", install_hint]]


def test_install_agent_warns_and_names_remote_source(monkeypatch, capsys):
def test_install_agent_warns_remote_installer_is_unverified_third_party(monkeypatch, capsys):
# Before the confirm, a remote installer must name the URL it fetches so the
# user consents to a specific source rather than blindly accepting.
monkeypatch.setattr(start.os, "name", "nt")
Expand All @@ -137,9 +138,23 @@ def test_install_agent_warns_and_names_remote_source(monkeypatch, capsys):
hint = "& ([scriptblock]::Create((irm https://hermes-agent.nousresearch.com/install.ps1))) -SkipSetup"
assert start._install_agent("hermes", hint) is None
err = capsys.readouterr().err
assert "Security warning" in err
assert "unverified third-party script" in err
assert "https://hermes-agent.nousresearch.com/install.ps1" in err
assert "download and RUN" in err
assert "signature or hash" in err
assert "Unsloth does not pin or verify the downloaded content" in err
assert "Continue only if you trust this source" in err


def test_install_agent_reports_immutable_remote_installer_pin(monkeypatch, capsys):
monkeypatch.setattr(start.os, "name", "posix")
monkeypatch.setattr(start.sys, "stdin", SimpleNamespace(isatty = lambda: True))
monkeypatch.setattr(start.typer, "confirm", lambda *a, **k: False)
assert start._install_agent("hermes", start._HERMES_POSIX_INSTALL_HINT) is None
err = capsys.readouterr().err
assert start._HERMES_INSTALL_COMMIT in err
assert "immutable upstream commit" in err
assert "does not independently verify or sandbox it" in err
assert "does not pin or verify" not in err


def test_install_agent_warns_for_package_installer(monkeypatch, capsys):
Expand All @@ -160,8 +175,8 @@ def test_hermes_install_hint_is_windows_native_on_windows(monkeypatch):
# Scriptblock form so `-SkipSetup` reaches the installer and the interactive
# setup wizard is skipped during the unattended `unsloth start hermes` run.
assert start._hermes_install_hint() == (
"& ([scriptblock]::Create((irm https://hermes-agent.nousresearch.com/install.ps1)))"
" -SkipSetup"
f"& ([scriptblock]::Create((irm {start._HERMES_INSTALL_BASE}/install.ps1)))"
f" -SkipSetup -Commit {start._HERMES_INSTALL_COMMIT}"
)


Expand All @@ -170,11 +185,20 @@ def test_hermes_install_hint_is_bash_on_posix(monkeypatch):

# `bash -s -- --skip-setup` forwards the skip flag to the piped installer.
assert start._hermes_install_hint() == (
"curl -fsSL https://raw.githubusercontent.com/NousResearch/hermes-agent"
"/main/scripts/install.sh | bash -s -- --skip-setup"
f"curl -fsSL {start._HERMES_INSTALL_BASE}/install.sh | bash -s --"
f" --skip-setup --commit {start._HERMES_INSTALL_COMMIT}"
)


def test_hermes_install_hints_pin_script_and_checkout_to_full_commit():
commit = start._HERMES_INSTALL_COMMIT
assert re.fullmatch(r"[0-9a-f]{40}", commit)
for hint in (start._HERMES_WINDOWS_INSTALL_HINT, start._HERMES_POSIX_INSTALL_HINT):
assert hint.count(commit) == 2
assert "/main/" not in hint
assert "hermes-agent.nousresearch.com" not in hint


def test_refresh_windows_path_noop_off_windows(monkeypatch):
monkeypatch.setattr(start.os, "name", "posix")
before = os.environ.get("PATH", "")
Expand Down