#!/usr/bin/env python3 """echo_secrets.py — M1: resolve the API bearer token without shipping it in source. [v1.0 SCAFFOLD — resolve_key() implemented; wiring into echo.py is the integration step] Problem: the token is hardcoded at echo.py:70 and repeated through api-reference.md / README — committed to git and shipped inside every .plugin zip, rotatable only by a rebuild. The plugin's own safety rule is "never store secrets". This resolves the key from progressively less-trusted sources, with a loud warning if the legacy baked default is ever reached. RESOLUTION ORDER (first hit wins): 1. env ECHO_KEY — preferred; CI / per-session override. 2. ECHO_STATE_DIR/credentials — local file, one `key=...` line, chmod 0600. 3. legacy baked default (deprecated) — warns to stderr; remove before 1.0 ship. Pure stdlib only (no `keyring`); the local file is the cross-platform stand-in for an OS keychain and keeps the secret OUT of the tracked tree. INTEGRATION (do at merge time): echo.py: KEY = echo_secrets.resolve_key() docs: replace the literal token with `` placeholders rotate: document `echo write-key` (writes the credentials file) — see TODO below """ from __future__ import annotations import os import sys from pathlib import Path # Kept ONLY so a fresh install still works during the migration window; delete for 1.0. _LEGACY_DEFAULT = "" # intentionally blank in the scaffold — do not re-introduce the literal def _state_dir() -> Path: return Path(os.environ.get("ECHO_STATE_DIR") or (Path.home() / ".echo-memory")) def _from_file() -> str | None: p = _state_dir() / "credentials" if not p.exists(): return None for line in p.read_text(encoding="utf-8").splitlines(): line = line.strip() if line.startswith("key=") or line.startswith("ECHO_KEY="): return line.split("=", 1)[1].strip() return None def resolve_key(legacy: str | None = None) -> str: """Return the bearer token from the most trusted available source: ECHO_KEY env -> credentials file -> `legacy` baked-in fallback (with a loud, once-per- process warning that can be silenced via ECHO_KEY_LEGACY_OK=1). Raises if none exist.""" env = os.environ.get("ECHO_KEY") if env: return env from_file = _from_file() if from_file: return from_file legacy = legacy or _LEGACY_DEFAULT if legacy: if os.environ.get("ECHO_KEY_LEGACY_OK") != "1": print("echo_secrets: WARNING — using the deprecated baked-in API key. Run " "`echo.py write-key ` (stores ~/.echo-memory/credentials) or set " "ECHO_KEY; set ECHO_KEY_LEGACY_OK=1 to silence.", file=sys.stderr) return legacy raise RuntimeError( "echo_secrets: no API key found. Set ECHO_KEY or create " f"{_state_dir() / 'credentials'} with a 'key=' line." ) def write_key(token: str) -> Path: """Persist the token to the local credentials file (one `key=...` line, chmod 0600). Best-effort perms — Windows has no POSIX mode bits, so the chmod is advisory there.""" d = _state_dir() d.mkdir(parents=True, exist_ok=True) path = d / "credentials" path.write_text(f"key={token.strip()}\n", encoding="utf-8") try: os.chmod(path, 0o600) except OSError: pass # platform without POSIX perms (e.g. some Windows filesystems) return path