Per CONVENTIONS.md Part 2 ("Never bare except") and CONVENTIONS.md
Part 7 (pre-commit hooks: ruff), blind `except Exception` is now a
lint failure. Pre-existing sites are marked `# noqa: BLE001` for
later manual review; new code must use specific exception types.
Changes:
- pyproject.toml: added "BLE" to ruff lint select. BLE001 is now enforced
- 103 of 166 `except Exception` sites were auto-converted to specific
types based on context (httpx, json, OSError, subprocess, etc.)
- 62 remaining sites marked with `# noqa: BLE001` for later review
(mostly generic try/except wrappers that legitimately need broad catch
for graceful degradation: e.g. compliance LLM fallback must catch
any error to preserve the regex result)
- 1 manual fix: reverted compliance.py LLM fallback to broad except
with explicit "must catch all errors" comment + noqa
- 2 files (commerce_sync.py, crm_sync.py) needed `import httpx` added
so the auto-converted exception references would resolve
- 5 source files (agency, monitor, pipelines, auth_connector,
llm_providers/registry) renamed "name" -> "<scope>_name" in
extra={...} dicts because "name" is a reserved LogRecord field
Test impact:
- 14 failing tests -> 1 (the SSE subprocess test is a sandbox limitation,
pre-existing and unrelated)
- New `test_ble_temp.py` verifies BLE001 catches new violations
Follow-up:
- Each `# noqa: BLE001` site should be reviewed and replaced with a
specific exception type where possible. The most common legitimate
broad-catch case is the LLM fallback path; everything else probably
can be narrowed.
The SECURITY.md contract said "use gopass" but the code only used
os.getenv. The deploy at /srv/pry/ had an .env file with secrets in
it, which violates the SECURITY.md threat model.
New module secrets_backend.py provides:
get_secret(name, default) - resolves from gopass, env, or file
set_secret(name, value) - writes to gopass
backend_info() - diagnostic dict for /health or /status
Backends selected by PRY_SECRET_BACKEND env var:
gopass (default) - reads from gopass at pry/<name>
env - reads from os.environ (PRY_<NAME> or PRY_<name>)
file - reads from PRY_ENV_FILE (default: PRY_DATA_DIR/.env)
auto - tries gopass, falls back to env
Refactored call sites:
auth.py: JWT_SECRET (was: os.getenv + ephemeral random default)
x402.py: X402_WALLET, X402_FACILITATOR_URL (was: os.getenv)
Seeded initial secrets on Talos (5 entries under pry/):
jwt_secret, api_key, x402_wallet, x402_facilitator, ollama_url
Updated .env.example header with backend selection guide and
seed-secret instructions.
Tests: 9/9 in test_secrets_backend.py pass. 36 tests in
test_x402_mcp_spec.py + test_secrets_backend.py all pass.
Verified end-to-end:
>>> import x402
>>> x402.X402_WALLET
'0xYourWalletAddressHere'
>>> import auth
>>> auth.JWT_SECRET
'change-me-rotate-quarterly'
Follow-up: rotate jwt_secret and api_key to real random values.
Document the rotation cadence in SECURITY.md.
Squashed from chore/license-relicense. Full message preserved in the
original branch commit bb77eb5. See ADR-0002 for the decision rationale.
Refs: ADR-0002, commit bb77eb5