codeflash-agent/packages/github-app/github_app/config.py
Kevin Turcios 2caaf6af7c
Fix CI: mypy errors, ruff formatting, switch to prek (#22)
* Fix mypy errors and apply ruff formatting across packages

Fix ast.FunctionDef calls missing type_params for Python 3.12+,
correct type: ignore error codes in _comparator and _plugin, and
run ruff format on all package source and test files.

* Switch CI to prek for lint/typecheck checks

Use j178/prek-action for consistent lint+typecheck (ruff check,
ruff format, interrogate, mypy) matching local pre-commit config.
Keep test as a separate parallel job for test-env support.
2026-04-15 02:52:47 -05:00

94 lines
2.7 KiB
Python

"""Environment-based configuration for the service."""
from __future__ import annotations
import os
from dataclasses import dataclass, field
from pathlib import Path
def load_private_key() -> str:
"""Load private key from env var (raw PEM) or file path."""
if raw := os.environ.get("GITHUB_PRIVATE_KEY"):
return raw
key_path = os.environ.get("GITHUB_PRIVATE_KEY_PATH", "")
if key_path:
return Path(key_path).read_text()
msg = "Set GITHUB_PRIVATE_KEY or GITHUB_PRIVATE_KEY_PATH"
raise ValueError(msg)
def default_plugin_dir() -> Path:
"""Default plugin dir is dist/ (assembled plugin) at the repo root."""
env = os.environ.get("PLUGIN_DIR")
if env:
return Path(env)
return Path(__file__).resolve().parents[3] / "dist"
@dataclass(frozen=True)
class Config:
"""Immutable configuration loaded from environment variables."""
# GitHub App credentials
app_id: int = field(
default_factory=lambda: int(os.environ["GITHUB_APP_ID"]),
)
private_key: str = field(default_factory=load_private_key)
webhook_secret: str = field(
default_factory=lambda: os.environ["GITHUB_WEBHOOK_SECRET"],
)
# Claude CLI
claude_cli: str = field(
default_factory=lambda: os.environ.get("CLAUDE_CLI", "claude"),
)
claude_model: str = field(
default_factory=lambda: os.environ.get(
"CLAUDE_MODEL",
"us.anthropic.claude-sonnet-4-5-20250929-v1:0",
),
)
plugin_dir: Path = field(default_factory=default_plugin_dir)
# Codex CLI
codex_cli: str = field(
default_factory=lambda: os.environ.get("CODEX_CLI", "codex"),
)
codex_model: str = field(
default_factory=lambda: os.environ.get(
"CODEX_MODEL",
"gpt-5.4",
),
)
# Backend selection
lead_backend: str = field(
default_factory=lambda: os.environ.get("LEAD_BACKEND", "claude"),
)
# Server
host: str = field(
default_factory=lambda: os.environ.get("HOST", "0.0.0.0"),
)
port: int = field(
default_factory=lambda: int(os.environ.get("PORT", "8000")),
)
# Repo workspace
workspace_dir: Path = field(
default_factory=lambda: Path(
os.environ.get(
"WORKSPACE_DIR",
"/tmp/codeflash-workspaces",
),
),
)
def cli_for_backend(self, name: str) -> str:
"""Return the CLI binary path for a backend name."""
return {"claude": self.claude_cli, "codex": self.codex_cli}[name]
def model_for_backend(self, name: str) -> str:
"""Return the model name for a backend name."""
return {"claude": self.claude_model, "codex": self.codex_model}[name]