Compare commits

...

2 Commits

Author SHA1 Message Date
kimi
063afe2573 fix: validate_startup checks CORS wildcard in production
All checks were successful
Tests / lint (pull_request) Successful in 4s
Tests / test (pull_request) Successful in 1m4s
validate_startup() now exits with an error if CORS_ORIGINS contains
a wildcard '*' in production mode, matching the runtime stripping
already done in _get_cors_origins().

Fixes #472

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-19 15:30:37 -04:00
0ae00af3f8 fix: remove AirLLM config settings from config.py (#475)
All checks were successful
Tests / lint (push) Successful in 4s
Tests / test (push) Successful in 1m18s
Co-authored-by: Kimi Agent <kimi@timmy.local>
Co-committed-by: Kimi Agent <kimi@timmy.local>
2026-03-19 15:24:43 -04:00
4 changed files with 26 additions and 12 deletions

View File

@@ -64,17 +64,10 @@ class Settings(BaseSettings):
# Seconds to wait for user confirmation before auto-rejecting.
discord_confirm_timeout: int = 120
# ── AirLLM / backend selection ───────────────────────────────────────────
# ── Backend selection ────────────────────────────────────────────────────
# "ollama" — always use Ollama (default, safe everywhere)
# "airllm" — always use AirLLM (requires pip install ".[bigbrain]")
# "auto" — use AirLLM on Apple Silicon if airllm is installed,
# fall back to Ollama otherwise
timmy_model_backend: Literal["ollama", "airllm", "grok", "claude", "auto"] = "ollama"
# AirLLM model size when backend is airllm or auto.
# Larger = smarter, but needs more RAM / disk.
# 8b ~16 GB | 70b ~140 GB | 405b ~810 GB
airllm_model_size: Literal["8b", "70b", "405b"] = "70b"
# "auto" — pick best available local backend, fall back to Ollama
timmy_model_backend: Literal["ollama", "grok", "claude", "auto"] = "ollama"
# ── Grok (xAI) — opt-in premium cloud backend ────────────────────────
# Grok is a premium augmentation layer — local-first ethos preserved.
@@ -476,6 +469,12 @@ def validate_startup(*, force: bool = False) -> None:
", ".join(_missing),
)
sys.exit(1)
if "*" in settings.cors_origins:
_startup_logger.error(
"PRODUCTION SECURITY ERROR: Wildcard '*' in CORS_ORIGINS is not "
"allowed in production — set explicit origins via CORS_ORIGINS env var."
)
sys.exit(1)
_startup_logger.info("Production mode: security secrets validated ✓")
else:
if not settings.l402_hmac_secret:

View File

@@ -826,7 +826,9 @@ class CascadeRouter:
Summary dict with added/removed/preserved counts.
"""
# Snapshot current runtime state keyed by provider name
old_state: dict[str, tuple[ProviderMetrics, CircuitState, float | None, int, ProviderStatus]] = {}
old_state: dict[
str, tuple[ProviderMetrics, CircuitState, float | None, int, ProviderStatus]
] = {}
for p in self.providers:
old_state[p.name] = (
p.metrics,

View File

@@ -220,7 +220,7 @@ def create_timmy(
print_response(message, stream).
"""
resolved = _resolve_backend(backend)
size = model_size or settings.airllm_model_size
size = model_size or "70b"
if resolved == "claude":
from timmy.backends import ClaudeBackend

View File

@@ -37,6 +37,19 @@ class TestConfigLazyValidation:
):
validate_startup(force=True)
def test_validate_startup_exits_on_cors_wildcard_in_production(self):
"""validate_startup() should exit in production when CORS has wildcard."""
from config import settings, validate_startup
with (
patch.object(settings, "timmy_env", "production"),
patch.object(settings, "l402_hmac_secret", "test-secret-hex-value-32"),
patch.object(settings, "l402_macaroon_secret", "test-macaroon-hex-value-32"),
patch.object(settings, "cors_origins", ["*"]),
pytest.raises(SystemExit),
):
validate_startup(force=True)
def test_validate_startup_ok_with_secrets(self):
"""validate_startup() should not exit when secrets are set."""
from config import settings, validate_startup