diff --git a/CHANGELOG.md b/CHANGELOG.md index fa9a825..be088a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.10.2] - 2026-01-07 + +### Bug Fixes + +- Fix SSL certificate verification for Nuitka binaries on macOS +- Fix macOS stdlib download URL (use PyPy 3.8 v7.3.11) + ## [0.10.1] - 2026-01-07 ### Enhancements diff --git a/pyproject.toml b/pyproject.toml index ba4de22..bb092d5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "shannot" -version = "0.10.1" +version = "0.10.2" description = "Sandboxed system administration for LLM agents" readme = "README.md" license = {text = "Apache-2.0"} diff --git a/shannot/config.py b/shannot/config.py index b178680..86d7dfe 100644 --- a/shannot/config.py +++ b/shannot/config.py @@ -82,9 +82,9 @@ def _xdg_config_home() -> Path: "sha256": "a23d21ca0de0f613732af4b4abb0b0db1cc56134b5bf0e33614eca87ab8805af", }, "darwin": { - "version": "7.3.17", # PyPy 3.8 - "url": "https://downloads.python.org/pypy/pypy3.8-v7.3.17-src.tar.bz2", - "sha256": "7491a669e3abc3420aca0cfb58cc69f8e0defda4469f503fd6cb415ec93d6b13", + "version": "7.3.11", # PyPy 3.8 + "url": "https://downloads.python.org/pypy/pypy3.8-v7.3.11-src.tar.bz2", + "sha256": "4d6769bfca73734e8666fd70503b7ceb06a6e259110e617331bb3899ca4e6058", }, } diff --git a/shannot/deploy.py b/shannot/deploy.py index 54948eb..250fd38 100644 --- a/shannot/deploy.py +++ b/shannot/deploy.py @@ -20,6 +20,7 @@ get_remote_deploy_dir, get_version, ) +from .runtime import get_ssl_context from .ssh import SSHConnection if TYPE_CHECKING: @@ -77,7 +78,8 @@ def _download_file(url: str, dest: Path, desc: str = "Downloading") -> None: try: request = urllib.request.Request(url, headers={"User-Agent": "shannot/1.0"}) - with urllib.request.urlopen(request) as response: + ssl_context = get_ssl_context() + with urllib.request.urlopen(request, context=ssl_context) as response: total_size = int(response.headers.get("Content-Length", 0)) downloaded = 0 diff --git a/shannot/runtime.py b/shannot/runtime.py index 1cd9da6..d123fc1 100644 --- a/shannot/runtime.py +++ b/shannot/runtime.py @@ -6,6 +6,7 @@ import os import platform import shutil +import ssl import sys import tarfile import tempfile @@ -32,6 +33,36 @@ class SetupError(Exception): pass +def get_ssl_context() -> ssl.SSLContext: + """Get SSL context that works on macOS with Nuitka binaries. + + Nuitka-compiled binaries on macOS can't find system SSL certificates. + This function tries multiple certificate locations. + """ + # Try default context first (works on most systems) + ctx = ssl.create_default_context() + + # On macOS, try known certificate locations if default fails verification + if platform.system() == "Darwin": + # Common certificate locations on macOS + cert_paths = [ + "/etc/ssl/cert.pem", # Homebrew OpenSSL + "/opt/homebrew/etc/openssl@3/cert.pem", # Homebrew ARM64 + "/usr/local/etc/openssl@3/cert.pem", # Homebrew x86_64 + "/opt/homebrew/etc/openssl/cert.pem", + "/usr/local/etc/openssl/cert.pem", + ] + for cert_path in cert_paths: + if os.path.exists(cert_path): + try: + ctx = ssl.create_default_context(cafile=cert_path) + break + except ssl.SSLError: + continue + + return ctx + + def is_runtime_installed() -> bool: """Check if runtime is installed and valid.""" return RUNTIME_LIB_PYTHON.is_dir() and RUNTIME_LIB_PYPY.is_dir() @@ -114,8 +145,9 @@ def download_with_progress( ) -> None: """Download URL to dest with optional progress reporting.""" request = urllib.request.Request(url, headers={"User-Agent": "shannot/1.0"}) + ssl_context = get_ssl_context() - with urllib.request.urlopen(request) as response: + with urllib.request.urlopen(request, context=ssl_context) as response: total_size = int(response.headers.get("Content-Length", 0)) downloaded = 0 diff --git a/uv.lock b/uv.lock index 47eba34..15c2168 100644 --- a/uv.lock +++ b/uv.lock @@ -793,7 +793,7 @@ wheels = [ [[package]] name = "shannot" -version = "0.10.0" +version = "0.10.2" source = { editable = "." } [package.optional-dependencies]