Commit graph

1 commit

Author SHA1 Message Date
Tejas Chopra
cb6c828457
fix(proxy): one bad extension no longer aborts proxy startup (#2215)
## What

`install_all()` (the `headroom.proxy_extension` loader) previously let
any exception from an extension's `install()` **propagate and abort
proxy startup** — one broken or version-incompatible third-party
extension took the whole proxy down, and every other extension with it.

This makes extension loading resilient:
- catch a failing `install()`, log it (with traceback), record it as
**skipped**
- continue installing the rest — a failure disables that one extension,
not the proxy
- print a `SKIPPED` line to the console (the startup banner lists
*enabled* extensions before install runs, so a skip would otherwise be
logging-config dependent)

## Why

Found while testing several proxy extensions together in a clean venv: a
plugin built against a newer core API raised `ModuleNotFoundError` from
`install()` and crashed the proxy at startup. An extension that fails
its own environment/auth check should disable itself — it should not
take the whole proxy down.

## Real behavior proof

Before — one extension failing in `install()`:
```
... proxy did NOT come up (/livez never answered)
```

After — same setup, one extension deliberately broken:
```
[headroom] proxy extensions SKIPPED: myorg_ext (install failed — running without them; see logs)
/livez: 200 healthy      # proxy up; the other extensions installed
```

Loader unit check (fake failing extension):
```
returned installed: ['good_ext']         # bad one excluded
bad_ext skipped (not in installed): True
good_ext survived: True
warning logged for bad_ext: True
```

## Tests

- `mypy headroom/proxy/extensions.py` → `Success: no issues found`
- `ruff check headroom/proxy/extensions.py` → `All checks passed!`
- Verified in-process (catch/skip/continue + logging) and end-to-end
against a running proxy (`/livez` 200 with a deliberately failing
extension).

## Maintainer Follow-up
- Added `tests/test_proxy_extensions.py` covering skip-and-continue
behavior for a failed extension and the missing-extension warning path.
- Removed an informal implementation comment from
`headroom/proxy/extensions.py`.
- Validation on `fe5176db`: `uv run --frozen --extra dev python -m
pytest tests/test_proxy_extensions.py -q`, `uvx ruff==0.15.17 check
headroom/proxy/extensions.py tests/test_proxy_extensions.py
--output-format concise`, `git diff --check`, and commit hooks all
passed.

---------

Co-authored-by: JerrettDavis <mxjerrett@gmail.com>
2026-07-14 22:50:03 -07:00