headroom/headroom
石岳峰 b7f342c153
fix(wrap): verify proxy deps before mutating Codex config (#1628)
## Description

\`headroom wrap codex\` now verifies that optional proxy dependencies
(\`headroom-ai[proxy]\`) are installed before mutating Codex
\`config.toml\`. If the check fails, the command exits with the same
error message as \`headroom proxy\` and leaves Codex config untouched.

Fixes #1614 (Bug 1: config mutated before proxy dependency check).

## Type of Change

- [x] Bug fix (non-breaking change that fixes an issue)
- [ ] New feature (non-breaking change that adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality to change)
- [ ] Documentation update
- [ ] Performance improvement
- [ ] Code refactoring (no functional changes)

## Changes Made

- Extract \`ensure_proxy_dependencies()\` in \`headroom/cli/proxy.py\`
(shared with \`headroom proxy\`)
- Call it at the start of \`wrap codex\` when \`not no_proxy\`, before
config snapshot/injection
- Add regression tests for prepare-only abort, \`--no-proxy\` skip, and
import failure messaging

## Testing

- [x] Unit tests pass (\`pytest\`)
- [x] Linting passes (\`ruff check .\`)
- [ ] Type checking passes (\`mypy headroom\`)
- [x] New tests added for new functionality
- [x] Manual testing performed

### Test Output

\`\`\`bash
pytest
tests/test_cli/test_wrap_codex.py::test_wrap_codex_aborts_before_mutating_config_when_proxy_deps_missing
\

tests/test_cli/test_wrap_codex.py::test_wrap_codex_skips_proxy_dependency_check_with_no_proxy
\

tests/test_cli/test_wrap_codex.py::test_ensure_proxy_dependencies_exits_when_server_import_fails
-q
# 3 passed
ruff check headroom/cli/wrap.py headroom/cli/proxy.py
tests/test_cli/test_wrap_codex.py
ruff format --check headroom/cli/wrap.py headroom/cli/proxy.py
tests/test_cli/test_wrap_codex.py
\`\`\`

## Real Behavior Proof

Environment: Linux (Ubuntu), Python 3.12, local checkout with
\`PYTHONPATH\` pointed at patched sources.

Exact command / steps:
1. Created a temp \`~/.codex/config.toml\` with \`model_provider =
"openai"\`.
2. Patched \`headroom.cli.wrap.ensure_proxy_dependencies\` to raise
\`SystemExit(1)\` (simulating missing \`[proxy]\` extra).
3. Ran \`headroom wrap codex --prepare-only --no-serena --port 8787\`.

Observed result: exit code 1; \`config.toml\` unchanged; no
\`config.toml.headroom-backup\` created; no \`[mcp_servers.headroom]\`
block written.

Also verified: \`headroom wrap codex --prepare-only --no-proxy ...\`
does not invoke the dependency check.

Not tested: Windows-specific proxy selector behavior (covered separately
in #1655).

## Review Readiness

- [x] I have performed a self-review
- [x] This PR is ready for human review

## Checklist

- [x] My code follows the project's style guidelines
- [x] I have performed a self-review of my code
- [x] I have commented my code, particularly in hard-to-understand areas
- [x] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] New and existing unit tests pass locally with my changes
- [x] I did not edit CHANGELOG.md; release notes are generated
automatically

---------

Co-authored-by: syf2211 <syf2211@users.noreply.github.com>
Co-authored-by: JerrettDavis <mxjerrett@gmail.com>
Co-authored-by: JD Davis <jd@jds-macbook-air.tail2a279.ts.net>
2026-08-13 11:52:22 -05:00
..
audit fix: remove rtk and lean-ctx CLI context tools (#2677) 2026-07-30 22:59:41 -07:00
backends fix(proxy): pass through cross-region prefixed Bedrock model IDs directly (#2330) 2026-08-11 23:54:03 -05:00
cache fix(cache): mirror client cache_control positions instead of single-marker consolidation 2026-08-11 18:15:44 -07:00
capture fix(cli): harden all CLI surfaces + fix docs accuracy (#1491) 2026-06-27 14:48:43 -07:00
ccr fix(ccr): verify a scanned marker's hash before advertising it (#2908) 2026-08-13 11:46:21 -05:00
cli fix(wrap): verify proxy deps before mutating Codex config (#1628) 2026-08-13 11:52:22 -05:00
compression fix(code): parse-probe tree-sitter availability in code_handler (#1231) (#1300) 2026-07-09 14:06:29 -05:00
dashboard feat: add deterministic runtime rollout controls (#1490) 2026-08-12 23:16:54 -05:00
evals feat(evals): weekly HotpotQA answer-recall report on the prose path (#1188) 2026-07-15 21:40:55 +00:00
graph refactor(wrap): retire tokensave; Serena is the code-memory MCP (#2499) 2026-07-22 20:59:24 -07:00
image fix(image): decouple routing types from trained_router so importing the compressor doesn't import torch (#2513) (#2537) 2026-08-12 00:22:56 -05:00
install feat: add deterministic runtime rollout controls (#1490) 2026-08-12 23:16:54 -05:00
integrations fix(litellm): close shared cloud client 2026-08-11 10:13:10 -07:00
learn fix(learn): stop classifying a successful exit code 0 as an error (#2289) 2026-08-11 23:45:32 -05:00
mcp_registry fix(wrap/serena): install Serena from the serena-agent PyPI wheel, not the git source 2026-08-11 09:10:32 -07:00
memory fix(memory): sanitize entity_refs to prevent dict-shaped entries crashing search (#2951) 2026-08-13 11:46:44 -05:00
models fix(models): version-boundary longest-prefix match in ModelRegistry.get (#1658) 2026-07-10 23:07:31 -05:00
observability fix(observability): aggregate tool savings in OTEL (#2936) 2026-08-11 22:54:55 -07:00
perf fix(stats): report one "Tokens Saved" headline across every harness (#2737) 2026-08-03 09:03:54 -07:00
pricing fix: Vertex model pricing shows $0.00 for versioned model names and vertex:anthropic provider (#2517) 2026-08-11 23:03:09 -05:00
providers fix(codex): route alpha search through the Codex backend (#2538) 2026-08-12 00:22:20 -05:00
proxy fix(proxy): relocate stray system-role messages to the top-level system param (#765) (#1357) 2026-08-13 11:52:09 -05:00
relevance feat(security): pilot hardening — stateless guarantee, model pinning, CI security gate (#1515) 2026-06-27 17:44:10 -07:00
reporting feat: attribute reread waste to over-compression via marker check (#901) 2026-06-13 10:43:35 -05:00
storage Fix 19 test failures: missing security attr, nosec inside f-strings, stale test mock 2026-04-07 18:30:29 -07:00
subscription fix(subscription): dedup transcript usage by message id (#2340 token inflation) (#2408) 2026-08-12 00:05:04 -05:00
telemetry fix(proxy/metrics): cap client-supplied model label cardinality (#2480) 2026-08-12 00:15:49 -05:00
testing test: add fluent Headroom harness (#2650) 2026-07-29 09:17:25 -07:00
tokenizers perf: cut hot-path latency 27% (token-count memo, startup preloads, JSON scan memo) (#2838) 2026-08-06 17:47:40 -07:00
transforms feat: add deterministic runtime rollout controls (#1490) 2026-08-12 23:16:54 -05:00
__init__.py Pin ORT dylib on Windows; init Python logging (#1010) 2026-06-23 07:46:24 -05:00
_ort.py fix(core): load ONNX Runtime dynamically so headroom._core imports on non-AVX2 x86-64 (#1715) 2026-07-14 13:25:41 -04:00
_subprocess.py ci: repair mypy no-any-return in _win32_pid_alive (#1556 follow-up) (#2336) 2026-07-16 20:55:17 -07:00
_version.py fix(version): mark source-checkout builds as -dev (#2072) 2026-07-13 09:38:17 -04:00
agent_savings.py fix(savings): coding profile compresses the recent delta (protect_recent 2->0, min_tokens 25->10) (#2145) 2026-07-14 04:07:25 -04:00
binaries.py chore: release main (#2792) 2026-08-12 19:02:51 -05:00
cli.py Add Click-based CLI with memory management commands 2026-01-29 21:30:21 -08:00
client.py refactor: DRY cache logic, add thread safety, fix Bash exclusion (#704) 2026-06-16 14:50:04 -05:00
compress.py feat(compress): expose frozen_message_count in library-mode compress() (#2178) 2026-07-14 16:07:21 -04:00
config.py feat: add deterministic runtime rollout controls (#1490) 2026-08-12 23:16:54 -05:00
context_tool_cleanup.py fix: remove rtk and lean-ctx CLI context tools (#2677) 2026-07-30 22:59:41 -07:00
copilot_auth.py feat(copilot): proxy VS Code models transparently (#2687) 2026-08-03 04:42:48 -07:00
copilot_linux_secret.py fix(windows): pin UTF-8 encoding on text-mode subprocess calls (#1311) 2026-06-23 12:52:49 -05:00
copilot_macos_keychain.py fix(windows): pin UTF-8 encoding on text-mode subprocess calls (#1311) 2026-06-23 12:52:49 -05:00
exceptions.py fix: B1 — retire ICM, RollingWindow, scoring, relevance + dependents 2026-05-02 12:23:17 -07:00
fsutil.py fix: remove rtk and lean-ctx CLI context tools (#2677) 2026-07-30 22:59:41 -07:00
hooks.py feat: introduce canonical pipeline lifecycle contract 2026-04-21 23:54:28 -05:00
offline.py feat(proxy): pilot hardening — inbound auth, security headers, audit log, air-gap switch (#1537) 2026-06-28 12:09:00 -07:00
onnx_runtime.py fix(onnx): stop ONNX thread pools from spinning idle cores (#2495) (#2540) 2026-08-08 01:33:57 -05:00
parser.py fix(agno): tolerate streaming tool-call SDK objects in parser (#1312) (#1336) 2026-06-24 09:52:15 -05:00
paths.py fix(wrap): serialize shared proxy startup (#2946) 2026-08-12 12:50:09 -07:00
pipeline.py feat: introduce canonical pipeline lifecycle contract 2026-04-21 23:54:28 -05:00
py.typed Prepare for OSS release v0.2.0 2026-01-07 11:36:44 -08:00
release_version.py ci(release): publish win_amd64 wheel so Windows installs need no Rust (#1328) (#1335) 2026-06-24 09:48:37 -05:00
rollout.py feat: add deterministic runtime rollout controls (#1490) 2026-08-12 23:16:54 -05:00
savings_ledger.py fix(savings): don't bill free models at the $3/M fallback in the ledger (#2147) 2026-07-14 12:19:30 -04:00
settings_store.py fix(ccr): resolve <<ccr:...>> markers inline when no retrieve-tool path exists (#2512) 2026-08-12 00:18:43 -05:00
shared_context.py fix(shared_context): don't evict an unrelated entry on an update at capacity (#2136) 2026-07-13 19:57:32 -04:00
tokenizer.py Initial commit: Headroom SDK - LLM context optimization toolkit 2026-01-06 23:16:58 -08:00
tools.json fix(review): address PR #210 feedback — race, query-params, SHA logging, frozen prefix, etc 2026-04-20 17:36:44 -07:00
update_check.py feat(proxy): pilot hardening — inbound auth, security headers, audit log, air-gap switch (#1537) 2026-06-28 12:09:00 -07:00
utils.py chore: add nosec B324 annotations to non-cryptographic MD5 usages and update temporary database path to use system temp directory 2026-04-07 13:07:26 +06:00