Merge pull request 'dev-race-condition-fixes' (#3) from dev-race-condition-fixes into main
All checks were successful
Publish to PyPI / publish (push) Successful in 14s

Reviewed-on: https://bitfreedom.net/code/code/nomyo-ai/nomyo/pulls/3
This commit is contained in:
Alpha Nerd 2026-04-09 13:05:14 +02:00
commit 302e47d980
4 changed files with 14 additions and 21 deletions

View file

@ -4,14 +4,13 @@ from cryptography.hazmat.primitives import serialization, hashes
from cryptography.hazmat.primitives.asymmetric import rsa, padding
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.primitives.kdf.hkdf import HKDF
# Setup module logger
logger = logging.getLogger(__name__)
# Import secure memory module
try:
from .SecureMemory import secure_bytearray, get_memory_protection_info, _get_secure_memory
from .SecureMemory import secure_bytearray, _get_secure_memory
_SECURE_MEMORY_AVAILABLE = True
except ImportError:
_SECURE_MEMORY_AVAILABLE = False
@ -77,19 +76,21 @@ class SecureCompletionClient:
- Response parsing
"""
def __init__(self, router_url: str = "https://api.nomyo.ai:12435", allow_http: bool = False):
def __init__(self, router_url: str = "https://api.nomyo.ai:12435", allow_http: bool = False, secure_memory: bool = True):
"""
Initialize the secure completion client.
Args:
router_url: Base URL of the NOMYO Router (must use HTTPS for production)
allow_http: Allow HTTP connections (ONLY for local development, never in production)
secure_memory: Whether to use secure memory operations for this instance.
"""
self.router_url = router_url.rstrip('/')
self.private_key = None
self.public_key_pem = None
self.key_size = 4096 # RSA key size
self.allow_http = allow_http # Store for use in fetch_server_public_key
self._use_secure_memory = _SECURE_MEMORY_AVAILABLE and secure_memory
# Validate HTTPS for security
if not self.router_url.startswith("https://"):
@ -122,7 +123,7 @@ class SecureCompletionClient:
- Rotate keys regularly
- Store keys outside the project directory in production
"""
if not _SECURE_MEMORY_AVAILABLE or not self.private_key:
if not self._use_secure_memory or not self.private_key:
return
try:
@ -416,7 +417,7 @@ class SecureCompletionClient:
aes_key = secrets.token_bytes(32) # 256-bit key
try:
if _SECURE_MEMORY_AVAILABLE:
if self._use_secure_memory:
with secure_bytearray(payload_json) as protected_payload:
with secure_bytearray(aes_key) as protected_aes_key:
return await self._do_encrypt(
@ -500,7 +501,7 @@ class SecureCompletionClient:
)
# Use secure memory to protect AES key and decrypted plaintext
if _SECURE_MEMORY_AVAILABLE:
if self._use_secure_memory:
with secure_bytearray(aes_key) as protected_aes_key:
ciphertext = base64.b64decode(package["encrypted_payload"]["ciphertext"])
nonce = base64.b64decode(package["encrypted_payload"]["nonce"])

View file

@ -51,6 +51,6 @@ try:
except ImportError:
pass
__version__ = "0.1.1"
__version__ = "0.2.2"
__author__ = "NOMYO AI"
__license__ = "Apache-2.0"

View file

@ -4,9 +4,9 @@ import uuid
from typing import Dict, Any, List, Optional
from .SecureCompletionClient import SecureCompletionClient
# Import secure memory module for configuration
# Check if secure memory module is available (used only for the user-facing warning)
try:
from .SecureMemory import disable_secure_memory, enable_secure_memory
from . import SecureMemory as _ # noqa: F401
_SECURE_MEMORY_AVAILABLE = True
except ImportError:
_SECURE_MEMORY_AVAILABLE = False
@ -69,20 +69,14 @@ class SecureChatCompletion:
key_dir: Directory to load/save RSA keys. If None, ephemeral keys are
generated in memory for this session only.
"""
self.client = SecureCompletionClient(router_url=base_url, allow_http=allow_http)
self.client = SecureCompletionClient(router_url=base_url, allow_http=allow_http, secure_memory=secure_memory)
self._keys_initialized = False
self._keys_lock = asyncio.Lock()
self.api_key = api_key
self._key_dir = key_dir
self._secure_memory_enabled = secure_memory
# Configure secure memory if available
if _SECURE_MEMORY_AVAILABLE:
if secure_memory:
enable_secure_memory()
else:
disable_secure_memory()
elif secure_memory:
if secure_memory and not _SECURE_MEMORY_AVAILABLE:
import warnings
warnings.warn(
"Secure memory requested but not available. "

View file

@ -4,7 +4,7 @@ build-backend = "hatchling.build"
[project]
name = "nomyo"
version = "0.2.1"
version = "0.2.2"
description = "OpenAI-compatible secure chat client with end-to-end encryption for NOMYO Inference Endpoints"
authors = [
{name = "NOMYO.AI", email = "ichi@nomyo.ai"},
@ -17,8 +17,6 @@ classifiers = [
"Intended Audience :: Information Technology",
"License :: OSI Approved :: Apache Software License",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
@ -27,7 +25,7 @@ classifiers = [
"Topic :: Communications :: Chat",
"Operating System :: OS Independent",
]
requires-python = ">=3.8"
requires-python = ">=3.10"
dependencies = [
"anyio==4.12.0",
"certifi==2025.11.12",