Commit graph

71 commits

Author SHA1 Message Date
dependabot[bot]
c8db13d5ad
deps: bump ruff from 0.16.2 to 0.16.3 in the pip-minor-patch group (#3143)
Bumps the pip-minor-patch group with 1 update:
[ruff](https://github.com/astral-sh/ruff).

Updates `ruff` from 0.16.2 to 0.16.3
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/ruff/releases">ruff's
releases</a>.</em></p>
<blockquote>
<h2>0.16.3</h2>
<h2>Release Notes</h2>
<p>Released on 2026-08-13.</p>
<h3>Preview features</h3>
<ul>
<li>[<code>pylint</code>] Fix false negatives on negative numbers
(<code>PLR6104</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27251">#27251</a>)</li>
<li>[<code>pyupgrade</code>] Add rule to replace <code>while 1</code>
with <code>while True</code> (<code>UP048</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27190">#27190</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>[<code>flake8-bandit</code>] Also check keyword arguments
(<code>S602</code>, <code>S603</code>, <code>S607</code>,
<code>S609</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27687">#27687</a>)</li>
<li>[<code>pylint</code>] Allow <code>continue</code> in
<code>finally</code> on Python 3.8 (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27626">#27626</a>)</li>
<li>[<code>pylint</code>] Fix <code>PLE1307</code> false positive with
bools (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27651">#27651</a>)</li>
<li>[<code>pylint</code>] Fix false positives and negatives with
<code>%b</code> format character (<code>PLE1300</code>,
<code>PLE1307</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27560">#27560</a>)</li>
<li>[<code>pylint</code>] Improve handling of concatenated strings
(<code>PLE1300</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27659">#27659</a>)</li>
</ul>
<h3>Rule changes</h3>
<ul>
<li>[<code>numpy</code>] Make <code>np.chararray</code> autofix
backwards-compatible (<code>NPY201</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27527">#27527</a>)</li>
</ul>
<h3>Performance</h3>
<ul>
<li>Enable PGO for Linux x86-64 Ruff releases (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27570">#27570</a>)</li>
<li>Enable PGO for Linux ARM64 Ruff releases (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27574">#27574</a>)</li>
<li>Enable PGO for Windows x86-64 Ruff releases (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27573">#27573</a>)</li>
<li>Enable PGO for macOS ARM64 Ruff releases (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27572">#27572</a>)</li>
<li>Reduce <code>Expr</code> size to 64 bytes (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27591">#27591</a>)</li>
</ul>
<h3>CLI</h3>
<ul>
<li>Hyperlink rule codes in <code>ruff check --statistics</code> output
(<a
href="https://redirect.github.com/astral-sh/ruff/pull/27646">#27646</a>)</li>
</ul>
<h3>Documentation</h3>
<ul>
<li>[<code>ruff</code>] Also suggest <code>asyncio.TaskGroup</code>
(<code>RUF006</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27461">#27461</a>)</li>
</ul>
<h3>Other changes</h3>
<ul>
<li>Use mimalloc v3 (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27586">#27586</a>)</li>
</ul>
<h3>Contributors</h3>
<ul>
<li><a
href="https://github.com/Andrej730"><code>@​Andrej730</code></a></li>
<li><a
href="https://github.com/alonfaraj"><code>@​alonfaraj</code></a></li>
<li><a
href="https://github.com/romero-deshaw"><code>@​romero-deshaw</code></a></li>
<li><a href="https://github.com/Avasam"><code>@​Avasam</code></a></li>
<li><a href="https://github.com/tjkuson"><code>@​tjkuson</code></a></li>
<li><a
href="https://github.com/charliermarsh"><code>@​charliermarsh</code></a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md">ruff's
changelog</a>.</em></p>
<blockquote>
<h2>0.16.3</h2>
<p>Released on 2026-08-13.</p>
<h3>Preview features</h3>
<ul>
<li>[<code>pylint</code>] Fix false negatives on negative numbers
(<code>PLR6104</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27251">#27251</a>)</li>
<li>[<code>pyupgrade</code>] Add rule to replace <code>while 1</code>
with <code>while True</code> (<code>UP048</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27190">#27190</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>[<code>flake8-bandit</code>] Also check keyword arguments
(<code>S602</code>, <code>S603</code>, <code>S607</code>,
<code>S609</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27687">#27687</a>)</li>
<li>[<code>pylint</code>] Allow <code>continue</code> in
<code>finally</code> on Python 3.8 (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27626">#27626</a>)</li>
<li>[<code>pylint</code>] Fix <code>PLE1307</code> false positive with
bools (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27651">#27651</a>)</li>
<li>[<code>pylint</code>] Fix false positives and negatives with
<code>%b</code> format character (<code>PLE1300</code>,
<code>PLE1307</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27560">#27560</a>)</li>
<li>[<code>pylint</code>] Improve handling of concatenated strings
(<code>PLE1300</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27659">#27659</a>)</li>
</ul>
<h3>Rule changes</h3>
<ul>
<li>[<code>numpy</code>] Make <code>np.chararray</code> autofix
backwards-compatible (<code>NPY201</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27527">#27527</a>)</li>
</ul>
<h3>Performance</h3>
<ul>
<li>Enable PGO for Linux x86-64 Ruff releases (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27570">#27570</a>)</li>
<li>Enable PGO for Linux ARM64 Ruff releases (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27574">#27574</a>)</li>
<li>Enable PGO for Windows x86-64 Ruff releases (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27573">#27573</a>)</li>
<li>Enable PGO for macOS ARM64 Ruff releases (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27572">#27572</a>)</li>
<li>Reduce <code>Expr</code> size to 64 bytes (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27591">#27591</a>)</li>
</ul>
<h3>CLI</h3>
<ul>
<li>Hyperlink rule codes in <code>ruff check --statistics</code> output
(<a
href="https://redirect.github.com/astral-sh/ruff/pull/27646">#27646</a>)</li>
</ul>
<h3>Documentation</h3>
<ul>
<li>[<code>ruff</code>] Also suggest <code>asyncio.TaskGroup</code>
(<code>RUF006</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27461">#27461</a>)</li>
</ul>
<h3>Other changes</h3>
<ul>
<li>Use mimalloc v3 (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27586">#27586</a>)</li>
</ul>
<h3>Contributors</h3>
<ul>
<li><a
href="https://github.com/Andrej730"><code>@​Andrej730</code></a></li>
<li><a
href="https://github.com/alonfaraj"><code>@​alonfaraj</code></a></li>
<li><a
href="https://github.com/romero-deshaw"><code>@​romero-deshaw</code></a></li>
<li><a href="https://github.com/Avasam"><code>@​Avasam</code></a></li>
<li><a href="https://github.com/tjkuson"><code>@​tjkuson</code></a></li>
<li><a
href="https://github.com/charliermarsh"><code>@​charliermarsh</code></a></li>
<li><a
href="https://github.com/chirizxc"><code>@​chirizxc</code></a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="b0e47022cf"><code>b0e4702</code></a>
Bump 0.16.3 (<a
href="https://redirect.github.com/astral-sh/ruff/issues/27723">#27723</a>)</li>
<li><a
href="ecdd401fdb"><code>ecdd401</code></a>
[ty] Separate script and uv modules from project metadata (<a
href="https://redirect.github.com/astral-sh/ruff/issues/27720">#27720</a>)</li>
<li><a
href="1263524672"><code>1263524</code></a>
[ty] Simplify display implementations with std::fmt::from_fn (<a
href="https://redirect.github.com/astral-sh/ruff/issues/27718">#27718</a>)</li>
<li><a
href="59196baedf"><code>59196ba</code></a>
[ty] Unify polarity-aware relation construction (<a
href="https://redirect.github.com/astral-sh/ruff/issues/27707">#27707</a>)</li>
<li><a
href="b8c5e73abe"><code>b8c5e73</code></a>
[ty] Disable CodSpeed cycle estimation for instrumented benchmarks (<a
href="https://redirect.github.com/astral-sh/ruff/issues/27706">#27706</a>)</li>
<li><a
href="2b0d21094e"><code>2b0d210</code></a>
[ty] Centralize matched argument relations (<a
href="https://redirect.github.com/astral-sh/ruff/issues/27705">#27705</a>)</li>
<li><a
href="a9130f3381"><code>a9130f3</code></a>
[<code>pyupgrade</code>] Add rule to replace <code>while 1</code> with
<code>while True</code> (<code>while-one</code>, `...</li>
<li><a
href="c64c7d6dad"><code>c64c7d6</code></a>
[ty] Model try exception flow with operation checkpoints (<a
href="https://redirect.github.com/astral-sh/ruff/issues/27471">#27471</a>)</li>
<li><a
href="9dea5ef180"><code>9dea5ef</code></a>
[ty] Avoid deriving sequents for typevars with concrete bounds (<a
href="https://redirect.github.com/astral-sh/ruff/issues/27587">#27587</a>)</li>
<li><a
href="9798e88de6"><code>9798e88</code></a>
[ty] Preserve enum exhaustiveness with custom <em>missing</em> methods
(<a
href="https://redirect.github.com/astral-sh/ruff/issues/27700">#27700</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/astral-sh/ruff/compare/0.16.2...0.16.3">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=ruff&package-manager=pip&previous-version=0.16.2&new-version=0.16.3)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: JerrettDavis <mxjerrett@gmail.com>
2026-08-20 21:31:48 -05:00
Tejas Chopra
df6ff6bd5b
fix(deps): bump datasets past PYSEC-2026-3716 (#3136)
## Why this is urgent

`datasets` 4.5.0 picked up **PYSEC-2026-3716** — path traversal in
folder-based dataset builders, where an unvalidated `file_name` metadata
field is joined to the dataset directory, so crafted traversal sequences
can read arbitrary local files into output on
`save_to_disk`/`push_to_hub`.

**The advisory was published today between 07:17 and 15:35 UTC.**
`main`'s audit passed at 07:17 on `17522fb0`; every PR run after 15:35
fails. So `Dependency audit (pip-audit)` is now **red repo-wide and
blocks all open PRs**, not just one.

## Exposure

Negligible for us. `datasets` is confined to the `evals` and
`voice-train` extras, and every call site in the repo uses
`load_dataset` against public Hub datasets — we never build folder-based
datasets from untrusted metadata, and never call
`save_to_disk`/`push_to_hub` on them.

But the gate audits the `[all]` production set and fails on any
actionable finding, so it has to be resolved rather than waived.

## The change

Bump both extras to `>=5.0.1` and relock. `load_dataset` — the only API
this repo touches — is unchanged across 2.x → 5.x.

Lock diff is **5 lines, `datasets` alone**; nothing else re-resolved.

## Verification

Ran the workflow's own command locally (`uv export --frozen --no-dev
--no-emit-project --no-hashes --extra all`, audited under Python 3.12 to
match CI):

```
No known vulnerabilities found
```

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Tejas Chopra <tejas@Tejass-MacBook-Pro.local>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 13:23:36 -07:00
Tejas Chopra
8156d4dc3a
fix(deps): raise the GitPython floor to 3.1.58 to clear 9 open advisories (#3120)
## Description

The reported advisory — **GHSA-956x-8gvw-wg5v** (High; command injection
via unguarded Git options in `Repo.archive()` / `git.ls_remote()`,
arbitrary file overwrite via `Repo.iter_commits()` / `Repo.blame()`) —
is fixed in GitPython **3.1.51**, and the lock already resolved to
**3.1.54**. So that specific advisory was not live exposure.

Checking the alert list rather than that one advisory turned up the real
problem: **nine other GitPython advisories are open against `uv.lock`**,
and 3.1.54 is inside all of their ranges.

| advisory | severity | affected | fixed in |
|---|---|---|---|
| GHSA-hmq2-w58f-27jc | High | ≤ 3.1.57 | 3.1.58 |
| GHSA-jm78-9fvv-mhgr | High | ≤ 3.1.57 | 3.1.58 |
| GHSA-wvpp-8hx9-p66j | High | ≤ 3.1.57 | 3.1.58 |
| GHSA-9rj7-rf2p-w77r | High | ≤ 3.1.57 | 3.1.58 |
| GHSA-4gmw-gg2m-w46p | High | ≤ 3.1.57 | 3.1.58 |
| GHSA-hh9p-6wh2-4mfc | Medium | ≤ 3.1.57 | 3.1.58 |
| GHSA-3f7w-8rr8-f37f | High | ≤ 3.1.56 | 3.1.57 |
| GHSA-539m-9xh6-q6rr | Medium | ≤ 3.1.56 | 3.1.57 |
| GHSA-p538-c434-8v24 | Medium | ≤ 3.1.55 | 3.1.56 |

The existing `[tool.uv] constraint-dependencies` floor was
`gitpython>=3.1.50`, set for an earlier batch, and had gone stale.

**Reachability:** GitPython is a transitive dependency (via `agno`) and
is imported nowhere in `headroom/`. This is a supply-chain floor bump,
not a fix to code we call.

## Type of Change

- [x] Bug fix (non-breaking change that fixes an issue)

## Changes Made

- `pyproject.toml`: raised the `constraint-dependencies` floor from
`gitpython>=3.1.50` to `>=3.1.58`, following the file's existing pattern
for transitive security floors, and replaced the stale comment with the
advisories it now covers. 3.1.58 is the highest fixed version across
**every** GitPython advisory published to date, so the floor clears all
of them rather than only the newest.
- `uv.lock`: regenerated with `uv lock --upgrade-package gitpython`;
resolves 3.1.54 → 3.1.59.

## Testing

- [x] Unit tests pass (`pytest`)
- [x] Manual testing performed

### Test Output

```text
tests/test_optional_dependencies.py tests/test_litellm_optional.py
tests/test_mcp_dependency_contract.py tests/test_onnx_dependency_contract.py
tests/test_toin_publish.py tests/test_release_workflows.py
1 failed, 61 passed, 1 skipped

Lock delta (263 packages before and after):
  ADDED   : none
  REMOVED : none
  CHANGED : {'gitpython': ('3.1.54', '3.1.59')}
```

The single failure is `test_no_native_tls_in_wheel_build_tree`,
pre-existing and environmental (no `cargo` on this machine); it fails
identically on a plain-`main` checkout.

## Real Behavior Proof

- Environment: macOS (darwin 25.4.0), Python 3.12.13, `uv` resolver,
worktree off `main` @ `b77d6129`
- Exact command / steps: (1) enumerated open Dependabot alerts and
cross-checked each against the GitHub advisory DB for GitPython to find
the highest required fixed version; (2) raised the floor and ran `uv
lock --upgrade-package gitpython`; (3) parsed both lockfiles and diffed
the full package→version map to confirm the blast radius; (4) ran the
dependency-contract test files.
- Observed result: resolver reports `Updated gitpython v3.1.54 ->
v3.1.59`. Full package-map diff shows 263 packages before and after with
**nothing added or removed and gitpython the only version change** — the
remaining ~230 lines of `uv.lock` diff are block reordering, not
content. `agno` declares gitpython with no version bound, and the clean
resolve confirms 3.1.59 satisfies every constraint in the graph.
- Not tested: no runtime exercise of GitPython itself, because nothing
in `headroom/` imports it — the meaningful integration check is the
`test-agno` CI job, which exercises the one package that does depend on
it.

## Runtime Rollout Safety

- Rollout-managed feature(s): None.
- Minimum rollout channel: n/a
- Stable/default behavior changed: No. Dependency floor only; no
`headroom` code changed.
- Kill switch / disable path: n/a — reverting the commit restores the
previous floor.
- Unsafe override required: No.
- Qualification impact: None.
- Rollback path: Revert this commit and re-run `uv lock`.

## Review Readiness

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

## Additional Notes

Found while investigating, **not fixed here**: the committed `sbom/`
snapshot is broadly stale — 37 packages disagree with `uv.lock`,
including `gitpython` (3.1.50) and `cryptography` (48.0.1 vs 50.0.0).
Nothing validates it against the lock; `publish.yml` generates a fresh
SBOM into `dist/` at release time, so the committed copy is a
point-in-time artifact. It is misleading for a security-facing file to
report a vulnerable version, but refreshing it is a separate change with
a large unrelated diff — worth its own issue.

Co-authored-by: Tejas Chopra <tejas@Tejass-MacBook-Pro.local>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 21:45:40 -07:00
dependabot[bot]
ff17961cd7
deps: bump ruff from 0.15.22 to 0.16.2 in the pip-minor-patch group across 1 directory (#2962)
Bumps the pip-minor-patch group with 1 update in the / directory:
[ruff](https://github.com/astral-sh/ruff).

Updates `ruff` from 0.15.22 to 0.16.2
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/ruff/releases">ruff's
releases</a>.</em></p>
<blockquote>
<h2>0.16.2</h2>
<h2>Release Notes</h2>
<p>Released on 2026-08-06.</p>
<h3>Bug fixes</h3>
<ul>
<li>[<code>flake8-pyi</code>] Avoid false positives on
<code>singledispatch</code> functions (<code>PYI041</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27335">#27335</a>)</li>
</ul>
<h3>Server</h3>
<ul>
<li>Register formatting capabilities dynamically to exclude TOML files
(<a
href="https://redirect.github.com/astral-sh/ruff/pull/27332">#27332</a>)</li>
</ul>
<h3>Contributors</h3>
<ul>
<li><a
href="https://github.com/MeGaGiGaGon"><code>@​MeGaGiGaGon</code></a></li>
<li><a
href="https://github.com/charliermarsh"><code>@​charliermarsh</code></a></li>
<li><a href="https://github.com/epage"><code>@​epage</code></a></li>
<li><a href="https://github.com/sharkdp"><code>@​sharkdp</code></a></li>
<li><a href="https://github.com/ntBre"><code>@​ntBre</code></a></li>
</ul>
<h2>Install ruff 0.16.2</h2>
<h3>Install prebuilt binaries via shell script</h3>
<pre lang="sh"><code>curl --proto '=https' --tlsv1.2 -LsSf
https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-installer.sh
| sh
</code></pre>
<h3>Install prebuilt binaries via powershell script</h3>
<pre lang="sh"><code>powershell -ExecutionPolicy Bypass -c &quot;irm
https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-installer.ps1
| iex&quot;
</code></pre>
<h2>Download ruff 0.16.2</h2>
<table>
<thead>
<tr>
<th>File</th>
<th>Platform</th>
<th>Checksum</th>
</tr>
</thead>
<tbody>
<tr>
<td><a
href="https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-aarch64-apple-darwin.tar.gz">ruff-aarch64-apple-darwin.tar.gz</a></td>
<td>Apple Silicon macOS</td>
<td><a
href="https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-aarch64-apple-darwin.tar.gz.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-x86_64-apple-darwin.tar.gz">ruff-x86_64-apple-darwin.tar.gz</a></td>
<td>Intel macOS</td>
<td><a
href="https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-x86_64-apple-darwin.tar.gz.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-aarch64-pc-windows-msvc.zip">ruff-aarch64-pc-windows-msvc.zip</a></td>
<td>ARM64 Windows</td>
<td><a
href="https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-aarch64-pc-windows-msvc.zip.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-i686-pc-windows-msvc.zip">ruff-i686-pc-windows-msvc.zip</a></td>
<td>x86 Windows</td>
<td><a
href="https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-i686-pc-windows-msvc.zip.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-x86_64-pc-windows-msvc.zip">ruff-x86_64-pc-windows-msvc.zip</a></td>
<td>x64 Windows</td>
<td><a
href="https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-x86_64-pc-windows-msvc.zip.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-aarch64-unknown-linux-gnu.tar.gz">ruff-aarch64-unknown-linux-gnu.tar.gz</a></td>
<td>ARM64 Linux</td>
<td><a
href="https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-aarch64-unknown-linux-gnu.tar.gz.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-i686-unknown-linux-gnu.tar.gz">ruff-i686-unknown-linux-gnu.tar.gz</a></td>
<td>x86 Linux</td>
<td><a
href="https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-i686-unknown-linux-gnu.tar.gz.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-powerpc64-unknown-linux-gnu.tar.gz">ruff-powerpc64-unknown-linux-gnu.tar.gz</a></td>
<td>PPC64 Linux</td>
<td><a
href="https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-powerpc64-unknown-linux-gnu.tar.gz.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-powerpc64le-unknown-linux-gnu.tar.gz">ruff-powerpc64le-unknown-linux-gnu.tar.gz</a></td>
<td>PPC64LE Linux</td>
<td><a
href="https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-powerpc64le-unknown-linux-gnu.tar.gz.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-riscv64gc-unknown-linux-gnu.tar.gz">ruff-riscv64gc-unknown-linux-gnu.tar.gz</a></td>
<td>RISCV Linux</td>
<td><a
href="https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-riscv64gc-unknown-linux-gnu.tar.gz.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-s390x-unknown-linux-gnu.tar.gz">ruff-s390x-unknown-linux-gnu.tar.gz</a></td>
<td>S390x Linux</td>
<td><a
href="https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-s390x-unknown-linux-gnu.tar.gz.sha256">checksum</a></td>
</tr>
</tbody>
</table>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md">ruff's
changelog</a>.</em></p>
<blockquote>
<h2>0.16.2</h2>
<p>Released on 2026-08-06.</p>
<h3>Bug fixes</h3>
<ul>
<li>[<code>flake8-pyi</code>] Avoid false positives on
<code>singledispatch</code> functions (<code>PYI041</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27335">#27335</a>)</li>
</ul>
<h3>Server</h3>
<ul>
<li>Register formatting capabilities dynamically to exclude TOML files
(<a
href="https://redirect.github.com/astral-sh/ruff/pull/27332">#27332</a>)</li>
</ul>
<h3>Contributors</h3>
<ul>
<li><a
href="https://github.com/MeGaGiGaGon"><code>@​MeGaGiGaGon</code></a></li>
<li><a
href="https://github.com/charliermarsh"><code>@​charliermarsh</code></a></li>
<li><a href="https://github.com/epage"><code>@​epage</code></a></li>
<li><a href="https://github.com/sharkdp"><code>@​sharkdp</code></a></li>
<li><a href="https://github.com/ntBre"><code>@​ntBre</code></a></li>
</ul>
<h2>0.16.1</h2>
<p>Released on 2026-07-30.</p>
<h3>Preview features</h3>
<ul>
<li>Add an option to opt out of human-readable names (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27160">#27160</a>)</li>
<li>[<code>flake8-pytest-style</code>] Make fixes safe by default and
unsafe only when comments are present (<code>PT018</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27201">#27201</a>)</li>
<li>[<code>pyupgrade</code>] Skip fix when a defaulted
<code>TypeVar</code> precedes a non-defaulted one (<code>UP040</code>,
<code>UP046</code>, <code>UP047</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27133">#27133</a>)</li>
<li>[<code>ruff</code>] Fix false positive with unpacked arguments
(<code>RUF065</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26959">#26959</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>Bump <code>gen-lsp-types</code> to gracefully handle unknown
enumeration values in LSP messages (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27230">#27230</a>)</li>
<li>[<code>flake8-bugbear</code>] Mark <code>range</code> as immutable
(<code>B008</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27247">#27247</a>)</li>
<li>[<code>flake8-comprehensions</code>] NFKC-normalize keyword names in
<code>C408</code> fix (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26813">#26813</a>)</li>
<li>[<code>flake8-return</code>] Fix false positive when variable is
read in <code>finally</code> clause (<code>RET504</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25441">#25441</a>)</li>
<li>[<code>pydocstyle</code>] Skip section detection inside RST
directive bodies (<code>D214</code>, <code>D405</code>,
<code>D413</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/23635">#23635</a>)</li>
<li>[<code>refurb</code>] Parenthesize <code>yield</code> arguments in
the <code>FURB192</code> fix (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27192">#27192</a>)</li>
</ul>
<h3>Rule changes</h3>
<ul>
<li>[<code>flake8-pytest-style</code>] Mark <code>PT022</code> fixes as
unsafe (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26440">#26440</a>)</li>
<li>[<code>refurb</code>] Mark fixes that remove unknown separators as
unsafe (<code>FURB105</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27200">#27200</a>)</li>
</ul>
<h3>Server</h3>
<ul>
<li>Fix indexing of excluded nested Ruff workspaces (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27303">#27303</a>)</li>
<li>Lint TOML files in the LSP (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26862">#26862</a>)</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="5b48a04097"><code>5b48a04</code></a>
Bump 0.16.2 (<a
href="https://redirect.github.com/astral-sh/ruff/issues/27555">#27555</a>)</li>
<li><a
href="1b9e5fc483"><code>1b9e5fc</code></a>
Update Swatinem/rust-cache action to v2.9.2 (<a
href="https://redirect.github.com/astral-sh/ruff/issues/27568">#27568</a>)</li>
<li><a
href="c4e86fc039"><code>c4e86fc</code></a>
[ty] Add helper extension methods for half-range and equality
constraints (<a
href="https://redirect.github.com/astral-sh/ruff/issues/2">#2</a>...</li>
<li><a
href="17a00de2e2"><code>17a00de</code></a>
[ty] Reuse primer commands in memory reports (<a
href="https://redirect.github.com/astral-sh/ruff/issues/27553">#27553</a>)</li>
<li><a
href="6ea296b969"><code>6ea296b</code></a>
[ty] Normalize type labels in structured docstrings (<a
href="https://redirect.github.com/astral-sh/ruff/issues/26923">#26923</a>)</li>
<li><a
href="2fc445f005"><code>2fc445f</code></a>
[ty] Diagnose invalid <strong>getattr</strong> calls (<a
href="https://redirect.github.com/astral-sh/ruff/issues/27502">#27502</a>)</li>
<li><a
href="22c7823c4e"><code>22c7823</code></a>
[ty] Enable (but downrank) auto-import completion suggestions from
stub-only ...</li>
<li><a
href="05160d507f"><code>05160d5</code></a>
[ty] Diagnose invalid descriptor <code>__get__</code> calls (<a
href="https://redirect.github.com/astral-sh/ruff/issues/27400">#27400</a>)</li>
<li><a
href="baea3d0dce"><code>baea3d0</code></a>
[ty] Expose strict analysis options in the playground (<a
href="https://redirect.github.com/astral-sh/ruff/issues/27543">#27543</a>)</li>
<li><a
href="c88946ebeb"><code>c88946e</code></a>
[ty] Bump ecosystem-analyzer for strict project settings (<a
href="https://redirect.github.com/astral-sh/ruff/issues/27542">#27542</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/astral-sh/ruff/compare/0.15.22...0.16.2">compare
view</a></li>
</ul>
</details>
<br />

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: JerrettDavis <mxjerrett@gmail.com>
2026-08-14 16:38:08 -05:00
JD Davis
a3fe5cb65b
fix(onnx): enforce Rust API-24 runtime compatibility (#2979)
## Description

Rust fastembed enables ORT C API 24, but the Python dependency allowed
ONNX Runtime 1.23.2. Entering ort's initializer with that library
deadlocks permanently instead of returning an error. Align dependency
resolution where compatible wheels exist and preflight native detection
where they do not.

Closes #2960

## 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

- Require ONNX Runtime 1.24+ for Python 3.11+ in the proxy and voice
extras.
- Keep the available pre-1.24 runtime on Python 3.10 for Python ONNX
consumers.
- Refuse to auto-pin an incompatible runtime into the Rust extension.
- Bypass native detection immediately when API 24 is unavailable,
preserving Python fallback without a five-second watchdog delay or stuck
native thread.
- Add dependency, pinning, override, and router regression coverage.

## 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

```text
$ uv run pytest -q tests/test_transforms/test_ort_dylib.py tests/test_onnx_dependency_contract.py tests/test_onnx_runtime.py tests/test_transforms/test_content_router.py
88 passed in 9.31s

$ uv run ruff check headroom/_ort.py headroom/transforms/content_router.py tests/test_transforms/test_ort_dylib.py tests/test_onnx_dependency_contract.py
All checks passed!
```

## Real Behavior Proof

- Environment: macOS arm64; Python 3.13.14 and uv-managed Python
3.10.20.
- Exact command / steps: run the issue's direct
`headroom._core.detect_content_type` call in a subprocess with a
12-second timeout on Python 3.13; run `_detect_content` on Python 3.10
after resolving the proxy extra.
- Observed result: Python 3.13 resolves ORT 1.26.0 and native detection
returns `json_array`; Python 3.10 resolves ORT 1.23.2, leaves
`ORT_DYLIB_PATH` unset, reports compatibility false, and immediately
returns the Python `json_array` fallback.
- Not tested: Linux-specific shared-object execution locally; CI's
existing Linux Rust job already preflights ORT 1.24+ and exercises
native tests.

## Runtime Rollout Safety

- Rollout-managed feature(s): Native Rust content detection.
- Minimum rollout channel: Stable/default; this is a deadlock prevention
guard.
- Stable/default behavior changed: Python 3.11+ installs a compatible
ORT; Python 3.10 skips incompatible native detection.
- Kill switch / disable path: `HEADROOM_DETECT_BACKEND=python` remains
available; an explicit `ORT_DYLIB_PATH` remains an operator override.
- Unsafe override required: No.
- Qualification impact: Native detection stays enabled only with
API-24-compatible ORT.
- Rollback path: Revert this PR, which restores the old watchdog-only
degradation.

## 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` — it is generated by
release-please from my Conventional Commit PR title (a CI guard enforces
this)

## Screenshots (if applicable)

Not applicable.

## Additional Notes

The large lockfile diff is dependency resolution: Python 3.10 keeps ORT
1.23.2 while 3.11+ resolves 1.26.0. The functional Python change is
intentionally small and keeps explicit `ORT_DYLIB_PATH` overrides
working.
2026-08-13 15:05:41 -05:00
JD Davis
6077e5a149
fix(mcp): restore SDK v1 compatibility cap (#2978)
## Description

PR #2963 widened the MCP dependency to 2.x while Headroom's live MCP
server still uses the v1 low-level `Server.list_tools()` and
`Server.call_tool()` decorators. Fresh installs therefore crash before
serving tools. Restore the v1 cap until the explicit SDK 2.x port in
#2658 lands, and pin that compatibility contract with a regression test.

Closes #2977

## 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

- Restore `mcp>=1.28.1,<2.0.0` in the `proxy` and `mcp` extras.
- Regenerate `uv.lock`, resolving MCP 1.28.1 and removing the
incompatible 2.x transitive set.
- Add a dependency-contract test covering both shipping extras.

## 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

```text
$ uv run pytest -q tests/test_mcp_dependency_contract.py tests/test_ccr_mcp_server.py tests/test_cli/test_mcp.py
41 passed in 0.56s

$ uv run ruff check tests/test_mcp_dependency_contract.py
All checks passed!

$ uv run ruff format --check tests/test_mcp_dependency_contract.py
1 file already formatted
```

## Real Behavior Proof

- Environment: macOS arm64, Python 3.13.14, uv-managed project
environment.
- Exact command / steps: resolve the `mcp` extra, inspect the installed
SDK version and v1 decorators, then instantiate
`HeadroomMCPServer(check_proxy=False)`.
- Observed result: `1.28.1 True True`; server construction returns a v1
`Server` successfully.
- Not tested: full stdio exchange against every external MCP client;
existing MCP unit and CLI suites cover server setup and handlers.

## Runtime Rollout Safety

- Rollout-managed feature(s): None; dependency resolution guard.
- Minimum rollout channel: Stable/default.
- Stable/default behavior changed: Fresh installs stop resolving the
incompatible MCP SDK 2.x release.
- Kill switch / disable path: Revert the dependency cap after #2658
lands.
- Unsafe override required: No.
- Qualification impact: MCP extras and proxy installs remain on the
maintained MCP 1.x line.
- Rollback path: Revert this PR; not recommended until the v2 server
port is merged and tested.

## 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` — it is generated by
release-please from my Conventional Commit PR title (a CI guard enforces
this)

## Screenshots (if applicable)

Not applicable.

## Additional Notes

The documentation change is the inline dependency rationale next to the
cap. The long-term migration remains #2658; this PR deliberately does
not mix that breaking SDK port into the release-blocker rollback.
2026-08-13 12:35:03 -05:00
dependabot[bot]
ecf130d3ac
deps: bump ruff from 0.15.17 to 0.15.22 in the pip-minor-patch group (#2501)
Bumps the pip-minor-patch group with 1 update:
[ruff](https://github.com/astral-sh/ruff).

Updates `ruff` from 0.15.17 to 0.15.22
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/ruff/releases">ruff's
releases</a>.</em></p>
<blockquote>
<h2>0.15.22</h2>
<h2>Release Notes</h2>
<p>Released on 2026-07-16.</p>
<h3>Preview features</h3>
<ul>
<li>[<code>pycodestyle</code>] Add an autofix for <code>E402</code> (<a
href="https://redirect.github.com/astral-sh/ruff/pull/22212">#22212</a>)</li>
<li>[<code>refurb</code>] Allow subclassing builtins in stub files
(<code>FURB189</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26812">#26812</a>)</li>
<li>[<code>ruff</code>] Add rule to replace <code>noqa</code> comments
with <code>ruff:ignore</code> (<code>RUF105</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26423">#26423</a>)</li>
<li>[<code>ruff</code>] Add rule to use human-readable names in
<code>ruff:ignore</code> comments (<code>RUF106</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26682">#26682</a>)</li>
<li>[<code>ruff</code>] Add rule to use human-readable names in
configuration selectors (<code>RUF201</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26772">#26772</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>[<code>flake8-pyi</code>] Fix false positive in <code>__all__</code>
(<code>PYI053</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26872">#26872</a>)</li>
</ul>
<h3>Rule changes</h3>
<ul>
<li>[<code>pylint</code>] Ignore mutable type updates in
<code>redefined-loop-name</code> (<code>PLW2901</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25733">#25733</a>)</li>
</ul>
<h3>Performance</h3>
<ul>
<li>Avoid redundant lexer token bookkeeping (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26765">#26765</a>)</li>
<li>Avoid redundant pending-indentation writes (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26774">#26774</a>)</li>
<li>Avoid unnecessary identifier lookahead (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26525">#26525</a>)</li>
<li>Reuse parser scratch buffers (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26798">#26798</a>)</li>
</ul>
<h3>Documentation</h3>
<ul>
<li>Document argfile support (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26803">#26803</a>)</li>
<li>[<code>flake8-datetimez</code>] Clarify naming guidance for
<code>datetime.today</code> (<code>DTZ002</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26658">#26658</a>)</li>
<li>[<code>pycodestyle</code>] Document <code>E731</code> fix safety (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26847">#26847</a>)</li>
<li>[<code>ruff</code>] Clarify intentional async contexts for
<code>unused-async</code> (<code>RUF029</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26641">#26641</a>)</li>
</ul>
<h3>Contributors</h3>
<ul>
<li><a href="https://github.com/dwego"><code>@​dwego</code></a></li>
<li><a
href="https://github.com/MichaReiser"><code>@​MichaReiser</code></a></li>
<li><a href="https://github.com/Joosboy"><code>@​Joosboy</code></a></li>
<li><a
href="https://github.com/KaufmanDmitriy"><code>@​KaufmanDmitriy</code></a></li>
<li><a
href="https://github.com/PeterJCLaw"><code>@​PeterJCLaw</code></a></li>
<li><a href="https://github.com/ntBre"><code>@​ntBre</code></a></li>
<li><a
href="https://github.com/charliermarsh"><code>@​charliermarsh</code></a></li>
</ul>
<h2>Install ruff 0.15.22</h2>
<h3>Install prebuilt binaries via shell script</h3>
<pre lang="sh"><code>&lt;/tr&gt;&lt;/table&gt; 
</code></pre>
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md">ruff's
changelog</a>.</em></p>
<blockquote>
<h2>0.15.22</h2>
<p>Released on 2026-07-16.</p>
<h3>Preview features</h3>
<ul>
<li>[<code>pycodestyle</code>] Add an autofix for <code>E402</code> (<a
href="https://redirect.github.com/astral-sh/ruff/pull/22212">#22212</a>)</li>
<li>[<code>refurb</code>] Allow subclassing builtins in stub files
(<code>FURB189</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26812">#26812</a>)</li>
<li>[<code>ruff</code>] Add rule to replace <code>noqa</code> comments
with <code>ruff:ignore</code> (<code>RUF105</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26423">#26423</a>)</li>
<li>[<code>ruff</code>] Add rule to use human-readable names in
<code>ruff:ignore</code> comments (<code>RUF106</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26682">#26682</a>)</li>
<li>[<code>ruff</code>] Add rule to use human-readable names in
configuration selectors (<code>RUF201</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26772">#26772</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>[<code>flake8-pyi</code>] Fix false positive in <code>__all__</code>
(<code>PYI053</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26872">#26872</a>)</li>
</ul>
<h3>Rule changes</h3>
<ul>
<li>[<code>pylint</code>] Ignore mutable type updates in
<code>redefined-loop-name</code> (<code>PLW2901</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25733">#25733</a>)</li>
</ul>
<h3>Performance</h3>
<ul>
<li>Avoid redundant lexer token bookkeeping (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26765">#26765</a>)</li>
<li>Avoid redundant pending-indentation writes (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26774">#26774</a>)</li>
<li>Avoid unnecessary identifier lookahead (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26525">#26525</a>)</li>
<li>Reuse parser scratch buffers (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26798">#26798</a>)</li>
</ul>
<h3>Documentation</h3>
<ul>
<li>Document argfile support (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26803">#26803</a>)</li>
<li>[<code>flake8-datetimez</code>] Clarify naming guidance for
<code>datetime.today</code> (<code>DTZ002</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26658">#26658</a>)</li>
<li>[<code>pycodestyle</code>] Document <code>E731</code> fix safety (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26847">#26847</a>)</li>
<li>[<code>ruff</code>] Clarify intentional async contexts for
<code>unused-async</code> (<code>RUF029</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26641">#26641</a>)</li>
</ul>
<h3>Contributors</h3>
<ul>
<li><a href="https://github.com/dwego"><code>@​dwego</code></a></li>
<li><a
href="https://github.com/MichaReiser"><code>@​MichaReiser</code></a></li>
<li><a href="https://github.com/Joosboy"><code>@​Joosboy</code></a></li>
<li><a
href="https://github.com/KaufmanDmitriy"><code>@​KaufmanDmitriy</code></a></li>
<li><a
href="https://github.com/PeterJCLaw"><code>@​PeterJCLaw</code></a></li>
<li><a href="https://github.com/ntBre"><code>@​ntBre</code></a></li>
<li><a
href="https://github.com/charliermarsh"><code>@​charliermarsh</code></a></li>
</ul>
<h2>0.15.21</h2>
<p>Released on 2026-07-09.</p>
<h3>Preview features</h3>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="0177a7e0d2"><code>0177a7e</code></a>
Bump 0.15.22 (<a
href="https://redirect.github.com/astral-sh/ruff/issues/26884">#26884</a>)</li>
<li><a
href="fe8ba85a55"><code>fe8ba85</code></a>
[<code>pycodestyle</code>] Document <code>E731</code> fix safety (<a
href="https://redirect.github.com/astral-sh/ruff/issues/26847">#26847</a>)</li>
<li><a
href="f3cf7c81fa"><code>f3cf7c8</code></a>
[<code>ruff</code>] Add <code>rule-codes-in-selectors</code>
(<code>RUF201</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/issues/26772">#26772</a>)</li>
<li><a
href="d244fd75e9"><code>d244fd7</code></a>
Document argfile support (<a
href="https://redirect.github.com/astral-sh/ruff/issues/26803">#26803</a>)</li>
<li><a
href="f23975849a"><code>f239758</code></a>
[<code>flake8-pyi</code>] Fix false positive in <code>__all__</code>
(<code>PYI053</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/issues/26872">#26872</a>)</li>
<li><a
href="54acbcde56"><code>54acbcd</code></a>
[ty] Support <code>TypeVarTuple</code> and <code>Unpack</code> (<a
href="https://redirect.github.com/astral-sh/ruff/issues/25240">#25240</a>)</li>
<li><a
href="87fc38cacd"><code>87fc38c</code></a>
[ty] Parallelize subtype hierarchy search (<a
href="https://redirect.github.com/astral-sh/ruff/issues/26875">#26875</a>)</li>
<li><a
href="e454f91fa6"><code>e454f91</code></a>
[ty] Share interned query keys across Salsa queries (<a
href="https://redirect.github.com/astral-sh/ruff/issues/26794">#26794</a>)</li>
<li><a
href="6f361a74a2"><code>6f361a7</code></a>
[ty] only collect expected types for files open in the editor (<a
href="https://redirect.github.com/astral-sh/ruff/issues/25546">#25546</a>)</li>
<li><a
href="6d6b2b3768"><code>6d6b2b3</code></a>
[ty] Avoid allocations during Salsa interned lookups (<a
href="https://redirect.github.com/astral-sh/ruff/issues/26877">#26877</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/astral-sh/ruff/compare/0.15.17...0.15.22">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=ruff&package-manager=pip&previous-version=0.15.17&new-version=0.15.22)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-10 17:31:36 -05:00
dependabot[bot]
74403fe804
build(deps): bump gitpython from 3.1.50 to 3.1.54 in the uv group across 1 directory (#2575)
Bumps the uv group with 1 update in the / directory:
[gitpython](https://github.com/gitpython-developers/GitPython).

Updates `gitpython` from 3.1.50 to 3.1.54
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/gitpython-developers/GitPython/releases">gitpython's
releases</a>.</em></p>
<blockquote>
<h2>3.1.54 - Security</h2>
<h2>What's Changed</h2>
<ul>
<li>Harden unsafe Git option validation by <a
href="https://github.com/Byron"><code>@​Byron</code></a> in <a
href="https://redirect.github.com/gitpython-developers/GitPython/pull/2180">gitpython-developers/GitPython#2180</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/gitpython-developers/GitPython/compare/3.1.53...3.1.54">https://github.com/gitpython-developers/GitPython/compare/3.1.53...3.1.54</a></p>
<h2>3.1.53 - Security</h2>
<h2>What's Changed</h2>
<ul>
<li>feat(submodule): add deinit method to Submodule (<a
href="https://redirect.github.com/gitpython-developers/GitPython/issues/2014">#2014</a>)
by <a href="https://github.com/mvanhorn"><code>@​mvanhorn</code></a> in
<a
href="https://redirect.github.com/gitpython-developers/GitPython/pull/2129">gitpython-developers/GitPython#2129</a></li>
<li>typing: introduce sensible basedpyright defaults by <a
href="https://github.com/Byron"><code>@​Byron</code></a> in <a
href="https://redirect.github.com/gitpython-developers/GitPython/pull/2174">gitpython-developers/GitPython#2174</a></li>
<li>fix: make <code>submodule.update()</code> after
<code>submodule.deinit()</code> work by <a
href="https://github.com/Byron"><code>@​Byron</code></a> in <a
href="https://redirect.github.com/gitpython-developers/GitPython/pull/2175">gitpython-developers/GitPython#2175</a></li>
<li>Fix commit hooks respecting core.hooksPath by <a
href="https://github.com/Siesta0217"><code>@​Siesta0217</code></a> in <a
href="https://redirect.github.com/gitpython-developers/GitPython/pull/2159">gitpython-developers/GitPython#2159</a></li>
<li>fix: validate config section delimiters by <a
href="https://github.com/Byron"><code>@​Byron</code></a> in <a
href="https://redirect.github.com/gitpython-developers/GitPython/pull/2176">gitpython-developers/GitPython#2176</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a
href="https://github.com/Siesta0217"><code>@​Siesta0217</code></a> made
their first contribution in <a
href="https://redirect.github.com/gitpython-developers/GitPython/pull/2159">gitpython-developers/GitPython#2159</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/gitpython-developers/GitPython/compare/3.1.52...3.1.53">https://github.com/gitpython-developers/GitPython/compare/3.1.52...3.1.53</a></p>
<h2>3.1.52 Security</h2>
<p><a
href="https://github.com/gitpython-developers/GitPython/security/advisories/GHSA-rwj8-pgh3-r573">https://github.com/gitpython-developers/GitPython/security/advisories/GHSA-rwj8-pgh3-r573</a>:
Environment-variable exfiltration via os.path.expandvars() on
Repo.clone_from() URL</p>
<h2>What's Changed</h2>
<ul>
<li>Skip cross-drive relative config test on Windows by <a
href="https://github.com/Byron"><code>@​Byron</code></a> in <a
href="https://redirect.github.com/gitpython-developers/GitPython/pull/2171">gitpython-developers/GitPython#2171</a></li>
<li>fix: preserve literal clone URLs by <a
href="https://github.com/Byron"><code>@​Byron</code></a> in <a
href="https://redirect.github.com/gitpython-developers/GitPython/pull/2172">gitpython-developers/GitPython#2172</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/gitpython-developers/GitPython/compare/3.1.51...3.1.52">https://github.com/gitpython-developers/GitPython/compare/3.1.51...3.1.52</a></p>
<h2>3.1.51 - Security</h2>
<h2>What's Changed</h2>
<ul>
<li>Add AI-disclosure and quality requirements to the contribution
guidelines by <a
href="https://github.com/Byron"><code>@​Byron</code></a> in <a
href="https://redirect.github.com/gitpython-developers/GitPython/pull/2143">gitpython-developers/GitPython#2143</a></li>
<li>docs(cmd): clarify Git.execute() string vs list command argument by
<a href="https://github.com/mvanhorn"><code>@​mvanhorn</code></a> in <a
href="https://redirect.github.com/gitpython-developers/GitPython/pull/2144">gitpython-developers/GitPython#2144</a></li>
<li>Rewrite Git.execute() command parameter docstring per <a
href="https://redirect.github.com/gitpython-developers/GitPython/issues/2146">#2146</a>
by <a href="https://github.com/EliahKagan"><code>@​EliahKagan</code></a>
in <a
href="https://redirect.github.com/gitpython-developers/GitPython/pull/2147">gitpython-developers/GitPython#2147</a></li>
<li>Document init script behavior with multiple master remotes by <a
href="https://github.com/EliahKagan"><code>@​EliahKagan</code></a> in <a
href="https://redirect.github.com/gitpython-developers/GitPython/pull/2148">gitpython-developers/GitPython#2148</a></li>
<li>Bump git/ext/gitdb from <code>335c0f6</code> to <code>0a019a2</code>
by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/gitpython-developers/GitPython/pull/2149">gitpython-developers/GitPython#2149</a></li>
<li>Support relative worktree paths (git 2.48+
worktree.useRelativePaths) by <a
href="https://github.com/elovelan"><code>@​elovelan</code></a> in <a
href="https://redirect.github.com/gitpython-developers/GitPython/pull/2151">gitpython-developers/GitPython#2151</a></li>
<li>Defer xfail condition evaluation with xfail_if_raises context
manager by <a
href="https://github.com/elovelan"><code>@​elovelan</code></a> in <a
href="https://redirect.github.com/gitpython-developers/GitPython/pull/2153">gitpython-developers/GitPython#2153</a></li>
<li>Run more submodule tests on Cygwin (fix flaky xfails) by <a
href="https://github.com/EliahKagan"><code>@​EliahKagan</code></a> in <a
href="https://redirect.github.com/gitpython-developers/GitPython/pull/2154">gitpython-developers/GitPython#2154</a></li>
<li>Cut xtrace noise from POSIX-ownership diagnostic steps by <a
href="https://github.com/EliahKagan"><code>@​EliahKagan</code></a> in <a
href="https://redirect.github.com/gitpython-developers/GitPython/pull/2156">gitpython-developers/GitPython#2156</a></li>
<li>Support index diffs against the empty tree by <a
href="https://github.com/puneetdixit200"><code>@​puneetdixit200</code></a>
in <a
href="https://redirect.github.com/gitpython-developers/GitPython/pull/2155">gitpython-developers/GitPython#2155</a></li>
<li>refactor: seperate out Progress type by <a
href="https://github.com/LoeschMaximilian"><code>@​LoeschMaximilian</code></a>
in <a
href="https://redirect.github.com/gitpython-developers/GitPython/pull/2157">gitpython-developers/GitPython#2157</a></li>
<li>Bump <a
href="https://github.com/astral-sh/ruff-pre-commit">https://github.com/astral-sh/ruff-pre-commit</a>
from v0.15.12 to 0.15.15 in the pre-commit group by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/gitpython-developers/GitPython/pull/2160">gitpython-developers/GitPython#2160</a></li>
<li>Bump actions/checkout from 6 to 7 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/gitpython-developers/GitPython/pull/2164">gitpython-developers/GitPython#2164</a></li>
<li>Bump git/ext/gitdb from <code>0a019a2</code> to <code>4950ea9</code>
by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/gitpython-developers/GitPython/pull/2165">gitpython-developers/GitPython#2165</a></li>
<li>Bump <a
href="https://github.com/astral-sh/ruff-pre-commit">https://github.com/astral-sh/ruff-pre-commit</a>
from v0.15.15 to 0.15.20 in the pre-commit group by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/gitpython-developers/GitPython/pull/2166">gitpython-developers/GitPython#2166</a></li>
<li>Add Commit.is_shallow property; document stats() limitation at
shallow boundary by <a
href="https://github.com/harshitayadavv"><code>@​harshitayadavv</code></a>
in <a
href="https://redirect.github.com/gitpython-developers/GitPython/pull/2167">gitpython-developers/GitPython#2167</a></li>
<li>Allow relative config paths with includes by <a
href="https://github.com/Byron"><code>@​Byron</code></a> in <a
href="https://redirect.github.com/gitpython-developers/GitPython/pull/2169">gitpython-developers/GitPython#2169</a></li>
<li>Reject abbreviated forms of unsafe git options by <a
href="https://github.com/Byron"><code>@​Byron</code></a> in <a
href="https://redirect.github.com/gitpython-developers/GitPython/pull/2168">gitpython-developers/GitPython#2168</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="e59d9bab02"><code>e59d9ba</code></a>
prepare next release</li>
<li><a
href="a4dc70d4ee"><code>a4dc70d</code></a>
Merge pull request <a
href="https://redirect.github.com/gitpython-developers/GitPython/issues/2180">#2180</a>
from gitpython-developers/single-char-kwarg</li>
<li><a
href="1d51b891d7"><code>1d51b89</code></a>
fix: guard diff output options</li>
<li><a
href="ffcb5359e8"><code>ffcb535</code></a>
fix: reject unsafe clone templates</li>
<li><a
href="e8d0fbf774"><code>e8d0fbf</code></a>
fix: validate split short-option values</li>
<li><a
href="faf3c09038"><code>faf3c09</code></a>
prepare for security fix</li>
<li><a
href="6a5eb6a534"><code>6a5eb6a</code></a>
Merge pull request <a
href="https://redirect.github.com/gitpython-developers/GitPython/issues/2176">#2176</a>
from gitpython-developers/fix-config-injection</li>
<li><a
href="1ed1b924f4"><code>1ed1b92</code></a>
fix: validate config section delimiters</li>
<li><a
href="354eb2fc50"><code>354eb2f</code></a>
Merge pull request <a
href="https://redirect.github.com/gitpython-developers/GitPython/issues/2159">#2159</a>
from Siesta0217/fix-core-hooks-path-commit-hooks</li>
<li><a
href="9bc287a2b1"><code>9bc287a</code></a>
Address review feedback about hook resolution</li>
<li>Additional commits viewable in <a
href="https://github.com/gitpython-developers/GitPython/compare/3.1.50...3.1.54">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=gitpython&package-manager=uv&previous-version=3.1.50&new-version=3.1.54)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions
You can disable automated security fix PRs for this repo from the
[Security Alerts
page](https://github.com/headroomlabs-ai/headroom/network/alerts).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-10 17:30:40 -05:00
Tejas Chopra
564e0a8d0f
fix(deps): bump h2 to 4.4.1 for CVE-2026-71554 (#2839)
## Description

`pip-audit` is currently red on every open PR. Not because of anything
in those branches — `uv.lock` pins `h2` at 4.3.0, and CVE-2026-71554 was
published against `h2 <=4.4.0`.

> h2 <=4.4.0 accepts request header blocks containing more than one Host
header, and forwards every Host header to the consuming application.
Where the consumer downgrades HTTP/2 to HTTP/1.1, the resulting request
carries two Host header lines, which is a request smuggling primitive
(CWE-444).

Fixed in 4.4.1.

Closes #

## 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

- `uv lock --upgrade-package h2`, which moves exactly two packages:

  ```
  h2     4.3.0 -> 4.4.1
  hpack  4.1.0 -> 4.2.0
  ```

`h2` arrives transitively via `httpx[http2]`, and the constraint in
`pyproject.toml` is already wide enough (`>=3,<5`), so only the lock
needed to move — no source or `pyproject.toml` change.
`requirements-prod.txt` is not checked in; the audit workflow exports it
from `uv.lock` at run time, so the lock bump is the entire fix.

## Testing

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

### Test Output

Reproduced the CI gate locally with the exact command from
`.github/workflows/security.yml`:

```text
$ uv export --frozen --no-dev --no-emit-project --no-hashes \
    --extra all --format requirements-txt > requirements-prod.txt

$ grep -E '^(h2|hpack)==' requirements-prod.txt
h2==4.4.1
hpack==4.2.0

$ pip-audit -r requirements-prod.txt
No known vulnerabilities found
```

Before this change, the same command reported:

```text
Name | Version | ID              | Fix Versions
h2   | 4.3.0   | CVE-2026-71554  | 4.4.1
Found 1 known vulnerability in 1 package
```

## Real Behavior Proof

- **Environment:** macOS, uv 0.9.x, Python 3.12.6.
- **Exact command / steps:** `uv lock --upgrade-package h2 --dry-run` to
confirm the blast radius, then the real lock, then the workflow's own
export + `pip-audit` invocation.
- **Observed result:** resolution touches only `h2` and `hpack`; 269
packages resolved with no other version movement. `pip-audit` goes from
1 known vulnerability to none.
- **Not tested:** HTTP/2 traffic against a live upstream. `h2` 4.4.1 is
a patch release on a library used transitively by `httpx`; Headroom does
not import `h2` directly (`grep -rn "import h2" headroom/` is empty), so
the exposure is whatever `httpx[http2]` does with it.

## 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
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] 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`

## Additional Notes

N/A items above: no code changed, so ruff/mypy/new tests do not apply —
the verification that matters is the audit output, which is quoted in
full.

**Why this is standalone.** It surfaced while fixing CI on #2838, but it
is not caused by that branch and it blocks #2832 identically. Landing it
separately unblocks the gate for every open PR at once and keeps a
supply-chain bump out of an unrelated change.

**One unrelated warning the resolver prints**, noted so it is not
mistaken for a side effect of this PR:

```
warning: `pypdfium2==5.12.0` is yanked (reason: "Setup blunder breaking some
bindgen codepaths ... Wheels are valid and effectively identical to 5.12.1")
```

That predates this change and is not touched by it. Worth its own bump,
but not here.
2026-08-06 17:46:51 -07:00
JD Davis
64e203931b
fix(deps): enforce audited transitive dependency floors (#2791)
## Description

Enforces patched minimum versions for the vulnerable transitive
`aiohttp` and `cryptography` dependencies so future lockfile refreshes
cannot reintroduce the pip-audit failures affecting open pull requests.

Related to the shared Security / pip-audit failures across open PRs.

## 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

- Enforces `aiohttp>=3.14.3` for PYSEC-2026-3545/3546/3547.
- Enforces `cryptography>=50.0.0` for PYSEC-2026-3552/3553/3554.
- Synchronizes the project version recorded in `uv.lock` with
`pyproject.toml`.

## Testing

- [x] Dependency audit passes (`pip-audit`)
- [x] Lockfile validation passes (`uv lock --check`)
- [ ] Unit tests pass (`pytest`)
- [ ] Type checking passes (`mypy headroom`)
- [x] Manual verification performed

### Test Output

```text
$ uv lock --check
Resolved 269 packages

$ uv export --frozen --no-dev --no-emit-project --no-hashes --extra all --format requirements-txt | uvx --python 3.12 pip-audit -r /dev/stdin
No known vulnerabilities found
```

## Real Behavior Proof

- Environment: Local macOS worktree using CPython 3.12.13 and the frozen
production dependency export.
- Exact command / steps: Validated the lockfile, exported every
production dependency with the `all` extra, and audited that exact
export with pip-audit.
- Observed result: The lockfile resolved successfully and pip-audit
reported no known vulnerabilities.
- Not tested: Publishing or deployment; the refreshed GitHub CI suite
covers builds, wheels, containers, security scans, and platform tests.

## Review Readiness

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

## Checklist

- [x] My code follows the project style guidelines
- [x] I have performed a self-review of my changes
- [x] No explanatory code comments are required beyond the PYSEC
constraint annotations
- [x] Documentation changes are not required for transitive security
floors
- [x] My changes generate no new local warnings
- [x] The dependency audit proves the security fix is effective
- [ ] Full repository tests are delegated to GitHub CI
- [x] I did not edit `CHANGELOG.md`; release-please owns it

## Screenshots (if applicable)

N/A — dependency metadata only.

## Additional Notes

The earlier Docker-native failure was a transient Docker Hub HTTP 502
while resolving `python:3.13-slim`; the build did not reach project
code. A fresh CI suite is running on the current head.

Co-authored-by: JD Davis <jd@jds-macbook-air.tail2a279.ts.net>
2026-08-05 08:33:38 -07:00
Tejas Chopra
0221e7f240
fix(deps): bump aiohttp and cryptography to clear the CVEs blocking 0.34.0 (#2753)
## Description

`Dependency audit (pip-audit)` is the **only** failing check on the
0.34.0 release PR (#2679), so this blocks the release regardless of what
else lands in it.

`aiohttp 3.14.1` carries three advisories, all reachable through the
`--extra all` production set that CI audits (transitive via `litellm` /
`instructor` / `kubernetes` / `fsspec`):

| CVE | Impact | Fixed in |
|---|---|---|
| CVE-2026-69243 | Request smuggling via an edge case in the WebSocket
upgrade procedure (server-side component) | 3.14.2 |
| CVE-2026-69244 | Out-of-bounds heap read in the C response parser
building an error message for a malformed response — an
attacker-controlled server can DoS the client | **3.14.3** |
| CVE-2026-59881 | Decompresses frames with RSV1 set even when
`permessage-deflate` was not negotiated | 3.14.2 |

3.14.3 is the floor that clears all three.

Closes #

## Type of Change

- [x] Bug fix (non-breaking change that fixes an issue)

## Changes Made

- Lock-only bump via `uv lock --upgrade-package aiohttp`. **No
`pyproject.toml` constraint added** — every parent already permits
3.14.3, so a floor would be redundant surface to maintain.
- The diff also syncs `headroom-ai` `0.32.0` → `0.33.0` in the lock. `uv
lock` rewrites that from `pyproject.toml` (`version = "0.33.0"`); the
lock's record of the project's own version was stale. Same drift #2663
targets — happy to drop this PR if #2663 lands first and you'd rather
keep them separate.

Diff is exactly two version changes (plus their wheel-hash blocks).

## Testing

- [x] Manual testing performed
- [x] Linting passes — no Python source touched

### Test Output

```text
$ uv lock --upgrade-package aiohttp
Resolved 269 packages in 2.91s
Updated aiohttp v3.14.1 -> v3.14.3
Updated headroom-ai v0.32.0 -> v0.33.0

$ git diff --stat uv.lock
 uv.lock | 456 +++++++++++++++++-------------------
 1 file changed, 234 insertions(+), 222 deletions(-)

$ git diff uv.lock | grep -E '^[+-]version = '
-version = "3.14.1"
+version = "3.14.3"
-version = "0.32.0"
+version = "0.33.0"
```

## Real Behavior Proof

- **Environment:** macOS 26.4 arm64, `uv` 0.x from Homebrew, isolated
git worktree off `upstream/main` @ `6422a80a`.

**(1) Reproduced the exact CI command** from
`.github/workflows/security.yml:48`:

```text
$ uv export --frozen --no-dev --no-emit-project --no-hashes --extra all --format requirements-txt
exported 620 lines
aiohttp==3.14.3
```

**(2) Confirmed against OSV** (the advisory source behind pip-audit)
rather than assuming the fix versions:

```text
aiohttp 3.14.1 -> 3 vulns
    GHSA-cq5v-8q36-5273 ['CVE-2026-69244']
    GHSA-mfx4-hv73-q22v ['CVE-2026-69243']
    GHSA-mq44-7p77-q5h7 ['CVE-2026-59881']
aiohttp 3.14.3 -> 0 vulns
```

- **Not tested:** `pip-audit` could not run locally — its isolated-venv
creation dies with an `ensurepip` SIGABRT on this machine, unrelated to
the repo. Hence the direct OSV query plus the real export as
verification. CI on this PR is the authoritative check.
- **Note:** the push warning reports 32 Dependabot alerts on the default
branch (19 high, 13 moderate). Those are separate from the `--extra all`
production set pip-audit gates on; this PR only clears the three that
fail that gate. Worth a separate sweep.

## 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] My changes generate no new warnings
- [x] I did **not** edit `CHANGELOG.md`

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-08-03 16:09:51 -07:00
Floze
2bb14d1ab2
fix(ci): align Ruff tooling versions (#2406)
## Description

Ruff currently has three independent versions: `uv.lock` resolves
`0.14.14`, pre-commit runs `0.9.4`, and CI installs `0.15.17`.
Contributors can therefore pass one formatter path and fail another.

Make the exact Ruff pin in `pyproject.toml` the source of truth, align
the lockfile and pre-commit hook to it, and make CI read that pin
through a deterministic consistency verifier instead of carrying another
hardcoded version.

Closes #2398

## 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 causes existing functionality
to change)
- [ ] Documentation update
- [ ] Performance improvement
- [ ] Code refactoring (no functional changes)

## Changes Made

- Pin the existing `[dev]` Ruff dependency to `0.15.17`, the formatter
baseline already used by CI.
- Refresh only Ruff in `uv.lock` with `uv 0.11.29`.
- Align `ruff-pre-commit` to `v0.15.17`.
- Add `scripts/verify-ruff-version.py` and run it from pre-commit and
CI.
- Make CI install the verified version read from `pyproject.toml` rather
than a separate literal.

## Testing

- [ ] Unit tests pass (`pytest`) — not run; no runtime source or test
behavior changed.
- [x] Linting passes (`ruff check .`)
- [x] Type checking passes (`mypy headroom`)
- [x] New deterministic guard proves the configuration fix
- [x] Manual testing performed

### Test Output

```text
# Before: run the verifier with the patched pyproject pin but base-branch
# uv.lock, pre-commit config, and workflow.
Ruff version mismatch detected:
  uv.lock uses Ruff 0.14.14, expected 0.15.17
  .pre-commit-config.yaml uses Ruff 0.9.4, expected 0.15.17
  ci.yml does not run 'python scripts/verify-ruff-version.py --print-version'
  ci.yml does not install Ruff from 'steps.ruff-version.outputs.version'

$ python3 scripts/verify-ruff-version.py
Ruff versions aligned at 0.15.17

$ uvx uv@0.11.29 lock --check
Resolved 269 packages

$ uvx uv@0.11.29 tree --locked --package ruff
ruff v0.15.17

$ uvx ruff@0.15.17 check .
All checks passed!

$ uvx ruff@0.15.17 format --check .
1322 files already formatted

$ uvx mypy@1.20.2 headroom --ignore-missing-imports
Success: no issues found in 505 source files

$ uvx --with tomli mypy@1.20.2 scripts/verify-ruff-version.py --ignore-missing-imports
Success: no issues found in 1 source file

$ uvx pre-commit run ruff --all-files
Passed
$ uvx pre-commit run ruff-format --all-files
Passed
$ uvx pre-commit run verify-ruff-version --all-files
Passed
```

## Real Behavior Proof

- Environment: macOS 26.5, Python 3.14.6 locally; Python 3.10 fallback
also exercised; `uv 0.11.29`, Ruff `0.15.17`, mypy `1.20.2`.
- Exact command / steps: reproduced the mismatch using the base branch's
real `uv.lock`, `.pre-commit-config.yaml`, and
`.github/workflows/ci.yml`; then ran the verifier, locked Ruff tree,
full Ruff check/format, mypy, and actual pre-commit hooks after the
patch.
- Observed result: the base state fails with all four drift points
listed; the patched state reports one aligned Ruff version (`0.15.17`)
and every formatter path passes.
- Not tested: runtime proxy behavior and the pytest suite, because the
change is limited to development-tool configuration, lock metadata,
pre-commit, and CI wiring.

## Dependency / Supply-Chain Justification

- Ruff is an existing development-only formatter maintained by Astral;
this PR adds no new package.
- `0.15.17` is required to fix local/CI reproducibility and has already
been the repository's CI formatter baseline since #1295.
- Install surface is limited to the `[dev]` extra, lint CI job, and
pre-commit environment. Production/runtime dependencies are unchanged.
- The `uv.lock` refresh updates only Ruff; no unrelated dependency
upgrades are included.

## 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 the non-obvious consistency checks
- [x] Documentation changes are N/A; contributor commands are unchanged
- [x] My changes generate no new warnings
- [x] The guard fails on the real base-state mismatch and passes after
the fix
- [ ] New and existing unit tests pass locally — not run; no runtime
code changed
- [x] I did not edit `CHANGELOG.md`; release-please will use the
conventional PR title

## Additional Notes

No formatter-driven source changes are included. AI assistance was used
to inspect configuration, implement the verifier, and run validation.
2026-07-18 20:55:20 -07:00
Abhay Singh
494fb5a60e
fix(security): exclude compromised ast-grep-cli 0.44.1 (supply-chain trojan) (#2342)
## Description

Fixes #2332.

The `ast_grep_cli` **0.44.1** PyPI release was a compromised
supply-chain build: it shipped an info-stealer `sg.exe` (212 KB,
detected as `Trojan:Win64/Lazy!MTB`) alongside the legitimate `ast-grep`
binary as camouflage. `headroom-ai` declares `ast-grep-cli>=0.30.0`, so
a fresh PyPI install — `pip install "headroom-ai[all]"` or `uv tool
install "headroom-ai[all]"` — can resolve the malicious 0.44.1 (the repo
`uv.lock` protects only `uv sync`-from-source, not end users installing
the published package).

## Fix

Exclude exactly the compromised version in the shipped dependency
metadata:

```toml
"ast-grep-cli>=0.30.0,!=0.44.1",
```

`!=0.44.1` removes only the known-bad build, so every other release
stays installable — older safe versions and any future patched release
alike. The committed `uv.lock` already resolves to the safe **0.42.1**,
which still satisfies the new constraint, so no re-resolution is needed;
I updated the lock's `requires-dist` entry to match the new specifier to
keep `uv lock --locked` consistent.

## 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

- `pyproject.toml`: `ast-grep-cli` constraint is now
`>=0.30.0,!=0.44.1`, with a comment recording why.
- `uv.lock`: update the `ast-grep-cli` `requires-dist` specifier to
match (resolved version unchanged at 0.42.1).

## Testing

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

### Test Output

```text
# Verified the specifier semantics with packaging:
$ python -c "from packaging.specifiers import SpecifierSet; from packaging.version import Version; s=SpecifierSet('>=0.30.0,!=0.44.1'); print(Version('0.44.1') in s, [str(v) for v in ['0.42.1','0.44.0','0.44.2','0.45.0'] if Version(v) in s])"
False ['0.42.1', '0.44.0', '0.44.2', '0.45.0']
# pyproject still parses and carries the new constraint:
$ python -c "import tomllib; print([d for d in tomllib.load(open('pyproject.toml','rb'))['project']['dependencies'] if 'ast-grep' in d])"
['ast-grep-cli>=0.30.0,!=0.44.1']
```

## Real Behavior Proof

- Environment: Windows 11, Python 3.12.
- Exact command / steps: evaluated the new
`SpecifierSet('>=0.30.0,!=0.44.1')` against the compromised version and
a range of safe versions, and re-parsed `pyproject.toml`.
- Observed result: `0.44.1` is excluded (`in` -> False); `0.42.1` (the
current lock pin), `0.44.0`, `0.44.2`, `0.45.0`, and `1.0.0` all remain
allowed; the pre-0.30 floor is still enforced. So a resolver can no
longer select the trojaned build, and no legitimate release is blocked.
- Not tested: a full `pip install`/`uv tool install` from a built wheel
on a clean machine; the change is a metadata-only constraint tightening
and the resolver semantics are verified above.

## 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
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] I have updated the CHANGELOG.md if applicable

## Additional Notes

This is the minimal, high-priority piece of the issue's recommended
actions (pin away from the compromised version). The issue also suggests
an install-docs warning and a `pip-audit` / `uv audit` CI step; those
are worth doing but are separate follow-ups (a CI workflow change I
can't meaningfully validate here), so I left them out to keep this fix
small and obviously correct. No CHANGELOG entry is added since this is a
dependency-metadata security pin, but I'm happy to add one if the
project prefers it here.

Co-authored-by: JerrettDavis <mxjerrett@gmail.com>
2026-07-17 12:10:30 -07:00
Tejas Chopra
0fa337f64f
build(deps): refresh stale uv.lock (reconcile ~30 missing deps) (#2349)
## Description

Refreshes the **stale `uv.lock`** and clears the mcp CVEs in one pass.
main's lock had drifted far from `pyproject.toml` — a full `uv lock`
(with the **CI-matching uv 0.11.29**, what `astral-sh/setup-uv@v5`
installs) reconciles ~30 declared-but-unlocked dependencies and their
transitives. This is the comprehensive counterpart to the minimal #2348.

Closes #

## Type of Change
- [x] Bug fix (security + dependency hygiene)

## Why it's this big
`uv lock --check` **fails on `main`** (the committed lock predates
several pyproject deps). CI hasn't caught it because the pipeline only
ever runs `uv export --frozen` (consume-as-is), never a re-lock — so the
drift accumulated silently. A correct lock is ~1100 lines of
reconciliation.

## Changes Made
- `pyproject.toml`: `mcp>=1.0.0` → `>=1.28.1` (core + `[mcp]` extra) —
carried from the security fix.
- `uv.lock`: full refresh via `uv lock` (uv 0.11.29). `mcp` → **1.28.1**
(clears CVE-2026-52869/52870/59950); ~30 previously-missing deps added;
transitives reconciled.

## Testing
```text
uv 0.11.29 lock --check   -> Resolved 269 packages (up to date, no error)
uv export --frozen ...    -> succeeds (CI pip-audit path)
mcp in refreshed lock     -> 1.28.1
```
The transitive version changes are what `uv lock` produces for the
current `pyproject.toml`; **CI's full test matrix is the validation
gate** for behavior (that's the point of the shards).

## Relationship to #2348
**Superset.** #2348 is the minimal, surgical mcp bump (5-line diff) for
immediate CVE closure with near-zero blast radius. This PR does the same
mcp fix **plus** the full stale-lock reconciliation. Merge **one**:
- Prefer low risk / fast → merge **#2348**, land this refresh separately
afterwards.
- Prefer fixing the lock drift now → merge **this**, close #2348.

No `CHANGELOG.md` edit (release-please owns it).
2026-07-17 04:08:59 -07:00
Tejas Chopra
a90be94e32
fix(deps): bump mcp to 1.28.1 to clear 3 high-severity CVEs (#2348)
## Description

Clears **all 3 open Dependabot alerts** (and the `pip-audit` CI failure)
— every one is `mcp 1.26.0` in `uv.lock`:

| Alert | CVE | Issue | Fix |
|-------|-----|-------|-----|
| #155 | CVE-2026-52870 | experimental task handlers leak cross-session
tasks | 1.27.2 |
| #156 | CVE-2026-52869 | HTTP transports serve session requests without
auth check | 1.27.2 |
| #157 | CVE-2026-59950 | deprecated WebSocket transport lacks
Host/Origin validation | 1.28.1 |

`mcp 1.28.1` satisfies all three.

Closes #

## Type of Change
- [x] Bug fix (security / dependency)

## Changes Made
- `pyproject.toml`: raise the floor `mcp>=1.0.0` → `mcp>=1.28.1` (core
dep **and** the `[mcp]` extra).
- `uv.lock`: bump the `mcp` entry `1.26.0` → `1.28.1` (version +
sdist/wheel URL, sha256, size from PyPI).

**Surgical on purpose.** mcp 1.28.1's resolved dependency set is
unchanged for this project's Python range (1.26 vs 1.28.1 differ only in
`python_version>=3.14` conditionals and an httpx upper bound already
satisfied), so no other locked package changes. Verified: `uv.lock`
parses, `mcp = 1.28.1`, no `mcp-1.26.0` refs remain.

## Testing
```text
python -c "import tomllib; ...; print(pkgs['mcp'])"  -> 1.28.1   (uv.lock valid TOML)
git diff --stat                                       -> pyproject.toml | 4 ; uv.lock | 6
grep -c mcp-1.26.0 uv.lock                            -> 0
```
mcp 1.28.1 ≥ every advisory's fixed-version, so all 3 alerts + pip-audit
clear.

## Real Behavior Proof
- Env: local; hashes fetched from
`https://pypi.org/pypi/mcp/1.28.1/json`.
- Steps: bumped the pyproject floor + the single mcp lock entry;
validated TOML + version + absence of old refs.
- Not tested: full `uv sync` (the lock is separately stale — see note).

## Note (deliberate scoping)
A full `uv lock` refresh churns ~900 lines: the lock is **separately
stale** (missing some declared deps) and local `uv` resolution diverges
(major downgrades of protobuf/posthog/portalocker — likely an env
artifact). That's a pre-existing lock-hygiene problem for its own PR —
**not** bundled into this security fix. No `CHANGELOG.md` edit
(release-please owns it).
2026-07-16 23:57:08 -07:00
Rudimar Ronsoni
dec60de976
fix(codex): preserve wrapped sessions and recover state (#2160)
## Description

Closes #2159.

Codex wrappers currently launch against a disposable `CODEX_HOME`, so
session state created during a wrapped run can disappear when that
temporary directory is removed. This change launches Codex against its
durable home, keeps proxy routing process-local, and adds recovery for
retained temporary homes and pinned recovery sources.

## 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)
- [x] Documentation update
- [ ] Performance improvement
- [ ] Code refactoring (no functional changes)

## Changes Made

- Launch Codex against its durable `CODEX_HOME` and apply routing
through process-local config overrides after the actual proxy port is
resolved.
- Preserve custom provider identity and reject providers that cannot be
redirected safely.
- Detect dangling temporary Codex homes before interactive wraps and
offer recovery.
- Add `headroom recover codex` with automatic discovery, repeatable
`--source`, preview, confirmation, retained backups, and rollback on
failure.
- Search Python's temp root, `$TMPDIR`, `/tmp`, `/private/tmp`, and
macOS `/private/var/folders/*/*/T` for retained `headroom-codex-home-*`
directories.
- Reuse `source-pinned/` copies left by interrupted or failed recovery
attempts after the original temporary home has disappeared.
- Report deleted temporary homes still referenced by SQLite rollout
paths without treating paths pasted into prompts or errors as filesystem
evidence.
- Audit the durable thread index, rollout files, and history when no
source remains, including indexed chat counts and history-only orphan
records.
- Normalize legacy localhost `headroom` providers in both SQLite thread
rows and rollout `session_meta`, including retries after an earlier
broken recovery, while preserving user-defined remote providers named
`headroom`.
- Merge compatible config, JSONL, rollout, SQLite, credential, and
regular-file state without propagating deletions or runtime artifacts.
- Rewrite recovered thread rollout paths to the durable home and restore
legacy Headroom thread providers to the active provider.
- Validate SQLite schemas, SQLx migration checksums, integrity, and
foreign keys, and quarantine malformed JSONL.
- Preserve failed targets with an atomic rename before rollback,
avoiding recursive-deletion races with live SQLite runtime files.
- Document discovery, migration, retained backups, rollback behavior,
and the limits of deleted-source recovery.

## Testing

- [x] Unit tests pass (`pytest`)
- [x] Linting passes (`ruff check`)
- [x] Type checking passes (`mypy`)
- [x] New tests added for new functionality
- [x] Manual testing performed in isolated Docker containers

### Test Output

```text
$ uv run pytest tests/test_cli/test_wrap_codex.py tests/test_cli/test_recover_codex.py -q
122 passed

$ uv run ruff check headroom/cli/recover.py headroom/providers/codex/recovery.py tests/test_cli/test_recover_codex.py
All checks passed!

$ uv run ruff format --check headroom/cli/recover.py headroom/providers/codex/recovery.py tests/test_cli/test_recover_codex.py
3 files already formatted

$ uv run mypy headroom/cli/recover.py headroom/providers/codex/recovery.py
Success: no issues found in 2 source files
```

All validation ran in `ghcr.io/astral-sh/uv:python3.12-bookworm` against
a writable disposable copy of a read-only source mount. Codex was not
installed or launched, and no real user Codex state was read or
modified.

The tests cover multi-root discovery, deleted-reference reporting,
retained pinned-source recovery, durable SQLite path relocation, SQLite
and rollout provider normalization, idempotent repair after an earlier
broken recovery, remote provider preservation, unrelated dangling target
rows, backup retention, atomic rollback, malformed-state quarantine,
SQLite validation, and Windows-safe handle closure.

The repository shim E2E was not launched locally because this recovery
work intentionally avoids launching Codex. Upstream CI exercises wrapper
E2E in isolated environments.

## Real Behavior Proof

- Environment: `ghcr.io/astral-sh/uv:python3.12-bookworm`, Python 3.12,
a writable disposable checkout copied from a read-only source mount, at
head `2d89ecec`.
- Exact command / steps: Run `pytest -q
tests/test_cli/test_wrap_codex.py tests/test_cli/test_recover_codex.py`,
then run `ruff check` and `ruff format --check` against
`headroom/cli/wrap.py`, `headroom/cli/recover.py`,
`headroom/providers/codex/recovery.py`,
`tests/test_cli/test_wrap_codex.py`, and
`tests/test_cli/test_recover_codex.py`.
- Observed result: `122 passed in 10.08s`; Ruff reported `All checks
passed!` and `5 files already formatted`.
- Not tested: Launching a real Codex process or modifying a real user
`CODEX_HOME`; these were intentionally excluded to protect live user
state.

## 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 where the behavior is hard to understand
- [x] I have made corresponding documentation changes
- [x] My changes generate no new warnings
- [x] I have added tests that prove the fix is effective
- [x] New and existing focused unit tests pass with my changes
- [x] I have updated `CHANGELOG.md` if applicable

## Additional Notes

The temporary-home behavior was introduced by #1507 in
`ad9d086f43`. Related context: #730, #731,
#961, #1034, #1050, #1349, #1853, #1889, #2103, and #2104.

A temporary home that macOS or `TemporaryDirectory` already deleted
cannot be reconstructed unless a retained `source-pinned/` copy exists.
Recovery identifies genuine dangling SQLite paths, audits surviving
durable history, and recovers any retained pinned source it can find.
Prompt text without a rollout cannot reconstruct a full transcript.

The unchecked changelog item is not applicable because this repository
does not require a changelog entry for this fix.

---------

Co-authored-by: JerrettDavis <mxjerrett@gmail.com>
2026-07-15 19:58:21 +00:00
LunarECL
fcf455a7eb
feat(wrap): add omp target (Oh My Pi) with models.yml override and unwrap (#1811)
## Description

Adds `headroom wrap omp` / `headroom unwrap omp` — a one-command wrap
for [Oh My Pi](https://www.npmjs.com/package/@oh-my-pi/pi-coding-agent)
(`omp`), the pi-mono-lineage coding agent, as proposed in #1149.

One honest correction to the issue: #1149 proposed reusing the
`ANTHROPIC_BASE_URL` redirect from `wrap claude`. During implementation
I probed that empirically and it turned out to be wrong — omp only reads
`ANTHROPIC_BASE_URL` in its web-search helper; its **chat** endpoint
comes from the model registry (`providers.anthropic.baseUrl` in
`~/.omp/agent/models.yml`). With the env var pointed at a local probe
server, omp's chat traffic still went straight to the real endpoint (0
probe hits); with a `models.yml` same-ID override, every request arrived
at the probe (9/9 hits on `/v1/messages`). A same-ID override keeps
omp's bundled Anthropic model catalog and stored credentials (both keyed
by provider id `anthropic`), so only the endpoint moves.

The wrap therefore injects a marker-fenced `providers.anthropic.baseUrl`
override into `models.yml`, snapshotting the pre-wrap file
**byte-for-byte** first, and `headroom unwrap omp` restores it exactly
(or removes the file when the wrap created it) — the same durable-wrap +
backup + unwrap contract `wrap codex` uses for `config.toml`.

Closes #1149

## Type of Change

- [ ] Bug fix (non-breaking change that fixes an issue)
- [x] 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

- `headroom/providers/omp/` (new provider slice): `models_yml_path()`
(honors `PI_CODING_AGENT_DIR`), `inject_models_override()` (yaml-merge
preserving user providers; pristine byte-for-byte backup, never
re-snapshotted while managed), `restore_models_override()` (`restored` /
`removed` / `noop`; never touches an unmanaged file),
`build_launch_env()`
- `headroom/cli/wrap.py`: `wrap omp` (mirrors the aider/vibe
`_launch_tool` shape; rtk instructions into the project's `AGENTS.md`,
which omp reads natively) and `unwrap omp` (restore models.yml + scrub
rtk block + stop proxy)
- `headroom/telemetry/context.py`: `omp` added to `_KNOWN_WRAP_AGENTS`
so the stack slug reports `wrap_omp` instead of `unknown`
- `README.md` (agent matrix row + unwrap list), `llms.txt`,
`CHANGELOG.md`
- `tests/test_cli/test_wrap_omp.py`: 16 tests (injection
fresh/merge/re-inject, restore statuses incl. unmanaged-file safety, env
passthrough, CLI wiring, unwrap flows)

## Testing

- [ ] Unit tests pass (`pytest`) — all new + `test_cli` tests pass; the
full suite carries **3 pre-existing failures** that reproduce
identically on unmodified `origin/main` (same set, same asserts — see
Test Output and the rebase-validation comment)
- [x] Linting passes (`ruff check .`)
- [x] Type checking passes (`mypy headroom`)
- [x] New tests added for new functionality
- [x] Manual testing performed

### Test Output

```text
$ uv run pytest -q                    # post-rebase, base 4f22cbb0
3 failed, 7723 passed, 515 skipped in 262.64s
  FAILED tests/test_cli/test_wrap_claude_base_url.py::test_wrap_marker_is_stale_when_pid_reused
  FAILED tests/test_rtk_session_savings.py::test_rtk_reader_returns_none_on_nonzero_exit
  FAILED tests/test_rtk_session_savings.py::test_lean_ctx_reader_returns_none_on_failure_and_logs
  → all three reproduce identically on unmodified origin/main (4f22cbb0), run the
    same way (same worktree + venv, sources switched): 3 failed, 7707 passed —
    this branch = baseline + the 16 new tests, nothing else changes.
    (The pre-rebase run against e8151f05 showed the same shape: one order-dependent
    flake that also reproduced on its baseline; these are env/order-dependent.)

$ uv run pytest tests/test_cli/ -q     # post-rebase
542 passed + 1 of the pre-existing failures above   # includes the 16 new test_wrap_omp.py tests

$ uv run ruff check . ; echo ruff-check-exit:$?
All checks passed!
ruff-check-exit:0

$ uv run ruff format --check .         # post-rebase
1 pre-existing violation: headroom/proxy/handlers/anthropic.py — flagged identically
on unmodified origin/main (not touched by this PR); every file this PR touches is clean

$ uv run mypy headroom               # post-rebase; output redirected to file; exit captured
Success: no issues found in 409 source files
mypy-exit:0
```

## Real Behavior Proof

- Environment: macOS 15 (arm64, M1 Pro), Python 3.12.13 (uv venv,
editable install incl. Rust `_core`), headroom @ this branch, base
extras only (no `[ml]`), Anthropic account signed into omp. Initial
proof ran on base e8151f05 with omp 16.3.6 (`@oh-my-pi/pi-coding-agent`
via bun); re-validated after the rebase onto 4f22cbb0 with omp 16.3.11 —
fresh numbers in the rebase-validation comment.

- Exact command / steps: four scenarios, run in this order —
1. Mechanism probe (why models.yml, not env): local HTTP probe server on
`127.0.0.1:18999`; ran `omp -p "say ok" --model claude-fable-5
--no-session --no-tools` once with
`ANTHROPIC_BASE_URL=http://127.0.0.1:18999`, once with
`~/.omp/agent/models.yml` containing `providers.anthropic.baseUrl:
http://127.0.0.1:18999`.
2. One-command path: `headroom wrap omp --no-rtk --port 8790 -- -p "Read
CHANGELOG.md and count how many '### Fixed' headings it contains. Answer
with just the number." --model claude-fable-5 --no-session --max-time
180`
3. Routing stats: separate proxy on :8788, wrap with `--no-proxy`, then
`GET /stats`.
4. Restore: `headroom unwrap omp`, plus an isolated
`PI_CODING_AGENT_DIR=/tmp/omp-agent-test` run with a pre-existing user
`models.yml`, then `cmp` against the original.

- Observed result: end-to-end routing through the proxy proven for every
scenario —
- Probe: env-var run → **0 probe hits**, omp answered normally
(bypassed). models.yml run → **9 hits on `/v1/messages?beta=true`** with
real Messages bodies. This is the routing mechanism the wrap uses.
- One-command run: wrap started the proxy ("Proxy ready on
http://127.0.0.1:8790"), wrote the override (`models.yml:
providers.anthropic.baseUrl=http://127.0.0.1:8790/p/headroom-wrap-omp`),
launched omp, and omp answered **"7"** (correct — real `read` tool work
through the proxy). Proxy log for the session (3 requests,
`anthropic_messages` path):
    ```
PERF model=claude-fable-5 msgs=1 tok_before=36 cache_read=0
cache_write=61939 cache_hit_pct=0
PERF model=claude-fable-5 msgs=3 tok_before=796 cache_read=0
cache_write=63308 cache_hit_pct=0
PERF model=claude-fable-5 msgs=5 tok_before=935 cache_read=63308
cache_write=215 cache_hit_pct=100
    ```
    Prompt caching survives the proxy (100% hit on the follow-up turn).
- Routing stats (:8788 session): `requests.total: 2, by_provider:
{"anthropic": 2}, by_model: {"claude-fable-5": 2}`, per-project prefix
`/p/headroom-wrap-omp` attributed.
- Unwrap: `Removed wrap-created models.yml` (file gone); isolated
pre-existing-file run: backup created, user's `my-gw` provider preserved
in the managed file, and after `unwrap omp` the restored file is
**byte-identical** (`cmp` clean).
- Compression: **not observed in this environment** — `tok_saved=0`,
`transforms=router:noop` / `too_small`. Honest reading: omp minimizes
its own tool outputs client-side (a 300-item JSON tool result reached
the proxy at only ~657 tokens) and the `[ml]` text compressor wasn't
installed; small print-mode payloads sit below crush thresholds, and
passthrough-by-default is the documented safety contract. The wrap's
value here is proven at the routing/lifecycle/cache layer; compression
numbers will match whatever the proxy does for a given content mix.

- Not tested: Windows / Linux; lean-ctx mode with omp
(`HEADROOM_CONTEXT_TOOL=lean-ctx` — `lean-ctx init --agent omp` depends
on lean-ctx recognizing the agent; failure degrades with a warning by
design); long interactive (non `-p`) sessions; `--memory` / `--learn` /
`--code-graph` flags combined with omp; OAuth-vs-API-key matrix beyond
my local account.

## 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
- [ ] New and existing unit tests pass locally with my changes — all
except the 3 documented pre-existing failures, which fail identically on
unmodified origin/main
- [x] I have updated the CHANGELOG.md if applicable

## Screenshots (if applicable)

N/A — terminal evidence inline above.

## Additional Notes

- The models.yml override is regenerated from the pristine backup on
every wrap, so re-running with a different `--port` updates the endpoint
idempotently and the backup is never clobbered.
- Scope note from #1149 stands: this routes omp's **Anthropic** provider
family. omp's other providers (OpenAI-direct, Gemini, ...) resolve their
endpoints from their own registry entries; users can already point those
at Headroom with their own custom provider in `models.yml`.
- `headroom/providers/omp/` deliberately contains no install-time / MCP
pieces — this is the thin wrap + unwrap slice only.

---------

Co-authored-by: JerrettDavis <mxjerrett@gmail.com>
Co-authored-by: Tejas Chopra <chopratejas@gmail.com>
2026-07-15 19:30:19 +00:00
JD Davis
cbfa267c5f
fix(deps): enforce transformers security floor (#2201)
## Description

Raise the production `transformers` dependency floor so the security
workflow cannot resolve the CVE-2026-5241 vulnerable range reported by
`pip-audit`, and refresh the small current-main test fixtures needed for
the PR matrix to run green.

## 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

- Raised direct optional `transformers` declarations for `proxy`, `ml`,
and `voice` extras to `>=5.5.0,<6.0`.
- Refreshed `uv.lock` metadata so `uv export --extra all` resolves a
patched `transformers` version for the production audit set.
- Kept the current-main test fixture fixes for the ZCode setup printer
and deferred compression fallback metrics.

## Testing

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

### Test Output

```text
$ uv lock --check
Resolved 238 packages in 1ms

$ uv export --frozen --no-dev --no-emit-project --no-hashes --extra all --format requirements-txt | rg "^transformers==|^huggingface-hub=="
huggingface-hub==1.16.1
transformers==5.13.1

$ uv export --frozen --no-dev --no-emit-project --no-hashes --extra all --format requirements-txt > requirements-prod.txt
$ uvx pip-audit -r requirements-prod.txt
No known vulnerabilities found

$ uv run --with pytest --with pytest-asyncio --with fastapi --with httpx --with numpy pytest tests/test_cli/test_wrap_zcode.py::test_wrap_prints_proxy_urls tests/test_cold_start_fast_pass.py::test_fast_pass_failure_falls_back_to_full_deferral -q
2 passed

$ uvx ruff==0.15.17 check headroom/cli/wrap.py headroom/proxy/handlers/anthropic.py --output-format concise
All checks passed!

$ git diff --check
passed
```

## Real Behavior Proof

- Environment: Windows checkout plus the same frozen production
dependency export shape used by the GitHub Actions security workflow.
- Exact command / steps: raised the `transformers` floor, refreshed
`uv.lock`, exported `--extra all` production requirements, ran
`pip-audit`, then reproduced the focused ZCode and deferred-compression
tests.
- Observed result: the export resolves `transformers==5.13.1`;
`pip-audit` reported no known vulnerabilities; the focused tests pass
locally; CI is rerunning on the updated head.
- Not tested: full GitHub Actions matrix locally; CI is running the
complete suite on this PR.

## 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
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] 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
- [ ] I have updated the CHANGELOG.md if applicable

## Screenshots (if applicable)

N/A - dependency metadata and CI fixture fix.

## Additional Notes

This PR is intentionally scoped to clearing the current red mainline
security gate while keeping the small fixture updates needed by the
branch test matrix.
2026-07-15 11:50:53 -05:00
JD Davis
ea3d5a86b7
fix(deps): clear Dependabot lockfile alerts (#2175)
## Description

Clears the current dependency/security-audit blockers that are making
unrelated PRs red:

- `transformers 5.3.0` / `CVE-2026-5241`, fixed by requiring
`transformers>=5.5.0` in the locked optional dependency set.
- `sqlitedict <=2.1.0` via the optional `benchmark` extra's
`lm-eval[api]` dependency. There is no patched `sqlitedict` release, so
this PR removes the published/locked `benchmark` extra instead of
shipping a known-vulnerable transitive dependency.
- `esbuild >=0.27.3,<0.28.1` in the OpenCode plugin lockfile, fixed by
forcing `esbuild@0.28.1` through the OpenCode npm override and
regenerated lockfile.

The benchmark code still invokes `python -m lm_eval`; researchers who
need that harness should install `lm-eval[api]` in their benchmark
environment until its transitive vulnerability has a patched release.

## 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

- `pyproject.toml`: remove the `benchmark` optional extra, document
external `lm-eval[api]` installation guidance, and require
`transformers>=5.5.0`.
- `uv.lock`: regenerate without the `benchmark` extra, removing
`lm-eval` and `sqlitedict` lock entries and locking the patched
transformers floor.
- `plugins/opencode/package.json`: add an `overrides` entry for
`esbuild@0.28.1`.
- `plugins/opencode/package-lock.json`: regenerate the OpenCode lockfile
with `esbuild@0.28.1`.

## Testing

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

### Test Output

```text
uv lock --check
rg -n -F 'sqlitedict' uv.lock        # no matches
rg -n -F 'name = "lm-eval"' uv.lock  # no matches
rg -n -F "extra == 'benchmark'" uv.lock # no matches
rg -n -F '0.27.7' plugins/opencode/package-lock.json plugins/opencode/package.json # no matches
npm ls esbuild --package-lock-only
npm audit --package-lock-only        # found 0 vulnerabilities
git diff --check
```

Previous GitHub checks were green. After merging current `main`, fresh
GitHub checks are running again; local targeted validation still passes.

## Real Behavior Proof

- Environment: Windows 11, Python 3.13.3, uv, npm in `plugins/opencode`,
Dependabot/pip-audit alert metadata from the failing PR jobs.
- Exact command / steps: inspected the regenerated Python and npm
lockfiles with `rg`, checked the uv lock with `uv lock --check`, checked
OpenCode's dependency tree with `npm ls esbuild --package-lock-only`,
and ran `npm audit --package-lock-only`.
- Observed result: `uv.lock` no longer contains `sqlitedict`, `lm-eval`,
or a `benchmark` extra marker; `transformers` resolves at the patched
`>=5.5.0` floor; OpenCode's lock resolves `esbuild@0.28.1`; `npm audit
--package-lock-only` reports 0 vulnerabilities; GitHub `Dependency audit
(pip-audit)` passes.
- Not tested: running the external `lm-eval` harness after installing it
separately.

## 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
- [ ] 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
- [ ] 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 have updated the CHANGELOG.md if applicable

## Screenshots (if applicable)

N/A - dependency and lockfile security fix.

## Additional Notes

The `benchmark` extra can be restored once the upstream `lm-eval[api]`
dependency chain stops pulling a vulnerable `sqlitedict` release.

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-07-14 20:40:28 -07:00
Rod Boev
4ea96a417c
feat(mcp): add streamable HTTP MCP transport (#1773)
## Description

`headroom mcp serve` only exposed stdio, which blocked MCP clients that
require a Streamable HTTP endpoint. This PR adds an explicit HTTP
transport mode around the existing Headroom MCP server while keeping
stdio as the default and keeping tool registration single-sourced.

Closes #1346.

## Type of Change

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

## Changes Made

- Add `headroom mcp serve --transport http` with host, port, and path
options.
- Serve `headroom_compress`, `headroom_retrieve`, and `headroom_stats`
through the same MCP server instance used by stdio.
- Keep `headroom mcp serve` defaulting to stdio for current Claude Code
and local MCP host configs.
- Update MCP docs for stdio and HTTP setup without implying the proxy
automatically owns `/mcp`.
- Keep the scope clean, rebased, and covered by focused tests.

## Testing

- [x] Unit tests pass (`uv run pytest tests/test_ccr_mcp_http.py
tests/test_cli/test_mcp.py -q`)
- [x] Linting passes (`uv run ruff check headroom/cli/mcp.py
headroom/ccr/mcp_server.py headroom/ccr/mcp_http.py
tests/test_ccr_mcp_http.py tests/test_cli/test_mcp.py`)
- [x] Type checking passes (`uv run mypy headroom
--ignore-missing-imports`)
- [x] New tests added for new functionality when applicable
- [x] Manual testing performed

### Test Output

```text
uv run pytest tests/test_ccr_mcp_http.py tests/test_cli/test_mcp.py -q
20 passed in 0.53s

uv run ruff check headroom/cli/mcp.py headroom/ccr/mcp_server.py headroom/ccr/mcp_http.py tests/test_ccr_mcp_http.py tests/test_cli/test_mcp.py
All checks passed!

uv run ruff format headroom/cli/mcp.py headroom/ccr/mcp_server.py headroom/ccr/mcp_http.py tests/test_ccr_mcp_http.py tests/test_cli/test_mcp.py --check
5 files already formatted

uv run mypy headroom --ignore-missing-imports
Success: no issues found in 407 source files
```

## Real Behavior Proof

- Environment: Local Python environment with Headroom dev dependencies
and MCP extra installed.
- Exact command / steps: Start `headroom mcp serve --transport http
--host 127.0.0.1 --port <test-port> --path /mcp`, then perform an MCP
SDK Streamable HTTP initialize/list-tools exchange.
- Observed result: The HTTP transport initializes and lists the existing
Headroom MCP tools; `headroom mcp serve` without `--transport` still
selects stdio, and mixed-case `--transport HTTP` routes to the HTTP
transport.
- Not tested: live validation against external MCP hosts

## Review Readiness

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

## Additional Notes

`CHANGELOG.md` is not edited because this repository generates changelog
entries from conventional commits. Full-suite validation is left to CI.
2026-07-14 13:25:45 -04:00
JD Davis
fce93bf39a
fix(ci/deps): clear audit and release smoke failures (#2190)
## Summary
- add a uv constraint floor for `setuptools>=83.0.0` to address
`PYSEC-2026-3447`
- refresh `uv.lock` so the production audit export resolves with
`setuptools 83.0.0`
- harden the Release wheel smoke-import gate by retrying
Ubuntu-container `apt-get` operations and using `--fix-missing`
- keep the generated `requirements-prod.txt` uncommitted; it is produced
by the security workflow

## Why
This clears the new dependency audit alert that made PRs red:

- `setuptools 80.10.2`
- `PYSEC-2026-3447`
- fixed in `83.0.0`

While validating the queue, the same PR class also hit a Release
smoke-import failure in the Ubuntu 22.04 ARM container due apt mirror
skew:

`E: Failed to fetch ... python3-httplib2_0.20.2-2ubuntu0.1_all.deb 404
Not Found`

The smoke gate should still fail for broken wheels, but transient apt
mirror skew should not make unrelated PRs red.

## Lockfile impact
- `setuptools 80.10.2 -> 83.0.0`
- `torch 2.12.1 -> 2.13.0`, required for pip resolver compatibility with
`setuptools 83.0.0` in the exported audit set
- `cuda-toolkit 13.0.2 -> 13.0.3.0`, pulled by the torch lock refresh
- uv also refreshed the existing project metadata for the sandbox extra
so `uv lock --check` passes

## Validation
- `uv lock --check`
- `uv export --frozen --no-dev --no-emit-project --no-hashes --extra all
--format requirements-txt > requirements-prod.txt`
- confirmed generated `requirements-prod.txt` contains
`setuptools==83.0.0`, `torch==2.13.0`, `cuda-toolkit==13.0.3.0`
- `uvx pip-audit -r requirements-prod.txt` -> No known vulnerabilities
found
- `python -m pytest tests/test_release_workflows.py -q` -> 32 passed
- `uvx ruff@0.15.17 check tests/test_release_workflows.py` -> All checks
passed
- `git diff --check`
2026-07-14 11:43:23 -04:00
dependabot[bot]
0e9bda8891
chore(deps): bump agno from 2.4.5 to 2.6.6 in the uv group across 1 directory (#2166)
Bumps the uv group with 1 update in the / directory:
[agno](https://github.com/agno-agi/agno).

Updates `agno` from 2.4.5 to 2.6.6
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/agno-agi/agno/releases">agno's
releases</a>.</em></p>
<blockquote>
<h2>v2.6.6</h2>
<h1>Changelog</h1>
<h2>New Features:</h2>
<ul>
<li><strong>Slack Interface:</strong> Added support for HITL multi-row
approvals with all pause types.</li>
</ul>
<h2>Improvements:</h2>
<ul>
<li><strong>WikiContextProvider:</strong> Added
<code>NotionDatabaseBackend</code> to wiki context provider.</li>
<li><strong>Tools:</strong> Updated to warn on duplicate tool names when
registering on agent or team.</li>
</ul>
<h2>Bug Fixes:</h2>
<ul>
<li><strong>JWT:</strong>
<ul>
<li>fixed to bind user_id to JWT subject in traces and approvals
routers</li>
<li>fixed to bind WebSocket user_id to JWT subject for workflows</li>
</ul>
</li>
<li><strong>RunOutput: f</strong>ixed
<code>aget_last_run_output</code> returns None when
<code>agent.id</code> is auto-generated during <code>arun()</code>.</li>
<li><strong><code>/continue</code> Endpoint:</strong> Fixed to forward
dependencies and metadata to /continue endpoints via
<code>get_request_kwargs</code>.</li>
<li><strong>LearningMachine:</strong> Fixed to inject LearningMachine
context into Team system prompt.</li>
</ul>
<h2>What's Changed</h2>
<ul>
<li>fix: bind user_id to JWT subject in traces and approvals routers by
<a href="https://github.com/ysolanky"><code>@​ysolanky</code></a> in <a
href="https://redirect.github.com/agno-agi/agno/pull/7816">agno-agi/agno#7816</a></li>
<li>fix: bind WebSocket user_id to JWT subject to prevent IDOR by <a
href="https://github.com/ysolanky"><code>@​ysolanky</code></a> in <a
href="https://redirect.github.com/agno-agi/agno/pull/7817">agno-agi/agno#7817</a></li>
<li>feat: add api client header to gemini connectors by <a
href="https://github.com/markmcd"><code>@​markmcd</code></a> in <a
href="https://redirect.github.com/agno-agi/agno/pull/7828">agno-agi/agno#7828</a></li>
<li>fix: warn on duplicate tool names when registering on agent or team
by <a href="https://github.com/ysolanky"><code>@​ysolanky</code></a> in
<a
href="https://redirect.github.com/agno-agi/agno/pull/7829">agno-agi/agno#7829</a></li>
<li>fix: add Anthropic context window patterns to
CONTEXT_WINDOW_PATTERNS by <a
href="https://github.com/marcospin"><code>@​marcospin</code></a> in <a
href="https://redirect.github.com/agno-agi/agno/pull/7836">agno-agi/agno#7836</a></li>
<li>fix: <code>aget_last_run_output</code> returns None when agent.id is
auto-generated during <code>arun()</code> by <a
href="https://github.com/kausmeows"><code>@​kausmeows</code></a> in <a
href="https://redirect.github.com/agno-agi/agno/pull/7840">agno-agi/agno#7840</a></li>
<li>fix: forward dependencies and metadata to /continue endpoints via
get_request_kwargs by <a
href="https://github.com/ysolanky"><code>@​ysolanky</code></a> in <a
href="https://redirect.github.com/agno-agi/agno/pull/7849">agno-agi/agno#7849</a></li>
<li>fix: inject LearningMachine context into Team system prompt by <a
href="https://github.com/Mustafa-Esoofally"><code>@​Mustafa-Esoofally</code></a>
in <a
href="https://redirect.github.com/agno-agi/agno/pull/7818">agno-agi/agno#7818</a></li>
<li>chore: update S3 bucket URL from phidata-public to agno-public by <a
href="https://github.com/irfaan101"><code>@​irfaan101</code></a> in <a
href="https://redirect.github.com/agno-agi/agno/pull/7844">agno-agi/agno#7844</a></li>
<li>fix: pin <code>tree-sitter-language-pack</code>&lt;1.8.0 to unblock
chonkie code chunker by <a
href="https://github.com/sannya-singal"><code>@​sannya-singal</code></a>
in <a
href="https://redirect.github.com/agno-agi/agno/pull/7869">agno-agi/agno#7869</a></li>
<li>feat: Slack HITL multi-row approvals with all pause types by <a
href="https://github.com/Mustafa-Esoofally"><code>@​Mustafa-Esoofally</code></a>
in <a
href="https://redirect.github.com/agno-agi/agno/pull/7574">agno-agi/agno#7574</a></li>
<li>fix: disable agno[mistral] (mistralai quarantined on PyPI) by <a
href="https://github.com/harshsinha03"><code>@​harshsinha03</code></a>
in <a
href="https://redirect.github.com/agno-agi/agno/pull/7877">agno-agi/agno#7877</a></li>
<li>[FIX] newsletter link in README by <a
href="https://github.com/kyleaton"><code>@​kyleaton</code></a> in <a
href="https://redirect.github.com/agno-agi/agno/pull/7900">agno-agi/agno#7900</a></li>
<li>cookbook: rewrite 01_demo as minimal AgentOS demo by <a
href="https://github.com/ashpreetbedi"><code>@​ashpreetbedi</code></a>
in <a
href="https://redirect.github.com/agno-agi/agno/pull/7906">agno-agi/agno#7906</a></li>
<li>feat: add NotionDatabaseBackend to wiki context provider by <a
href="https://github.com/ashpreetbedi"><code>@​ashpreetbedi</code></a>
in <a
href="https://redirect.github.com/agno-agi/agno/pull/7914">agno-agi/agno#7914</a></li>
<li>chore: Release v2.6.6 by <a
href="https://github.com/kausmeows"><code>@​kausmeows</code></a> in <a
href="https://redirect.github.com/agno-agi/agno/pull/7915">agno-agi/agno#7915</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/markmcd"><code>@​markmcd</code></a> made
their first contribution in <a
href="https://redirect.github.com/agno-agi/agno/pull/7828">agno-agi/agno#7828</a></li>
<li><a href="https://github.com/marcospin"><code>@​marcospin</code></a>
made their first contribution in <a
href="https://redirect.github.com/agno-agi/agno/pull/7836">agno-agi/agno#7836</a></li>
<li><a href="https://github.com/irfaan101"><code>@​irfaan101</code></a>
made their first contribution in <a
href="https://redirect.github.com/agno-agi/agno/pull/7844">agno-agi/agno#7844</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/agno-agi/agno/compare/v2.6.5...v2.6.6">https://github.com/agno-agi/agno/compare/v2.6.5...v2.6.6</a></p>
<h2>v2.6.5</h2>
<h1>Changelog</h1>
<h2>New Features:</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="948cb4685c"><code>948cb46</code></a>
chore: Release v2.6.6 (<a
href="https://redirect.github.com/agno-agi/agno/issues/7915">#7915</a>)</li>
<li><a
href="90b10d4b21"><code>90b10d4</code></a>
feat: add NotionDatabaseBackend to wiki context provider (<a
href="https://redirect.github.com/agno-agi/agno/issues/7914">#7914</a>)</li>
<li><a
href="0b5a79fb7a"><code>0b5a79f</code></a>
chore: update readme</li>
<li><a
href="a4a552d713"><code>a4a552d</code></a>
chore: update readme</li>
<li><a
href="ff6aa1e218"><code>ff6aa1e</code></a>
chore: update readme</li>
<li><a
href="550c4f9ef7"><code>550c4f9</code></a>
chore: update readme</li>
<li><a
href="7bcdfcf94a"><code>7bcdfcf</code></a>
chore: update readme</li>
<li><a
href="37897dd238"><code>37897dd</code></a>
chore: update readme</li>
<li><a
href="d2cb873705"><code>d2cb873</code></a>
chore: update readme</li>
<li><a
href="db1a3cbd35"><code>db1a3cb</code></a>
chore: update readme</li>
<li>Additional commits viewable in <a
href="https://github.com/agno-agi/agno/compare/v2.4.5...v2.6.6">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=agno&package-manager=uv&previous-version=2.4.5&new-version=2.6.6)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions
You can disable automated security fix PRs for this repo from the
[Security Alerts
page](https://github.com/headroomlabs-ai/headroom/network/alerts).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-13 23:22:15 -05:00
Rod Boev
e9000863fc
fix(kompress): fail-open wall-clock guard on single-cache-miss compression (#2114)
## Description

The single-cache-miss branch in `ContentRouter` ran compression inline
on the request path without its own wall-clock guard, so a cooperative
stall waited for the full call even when
`HEADROOM_COMPRESSION_DEADLINE_MS` was meant to fail open. This change
adds a branch-level watchdog that returns `PASSTHROUGH` after the
deadline, scoped only to the one-pending-task path and not the native
GIL-hold root cause.

Closes #2046

## 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

- Added `_compression_deadline_seconds()` and a watchdog around the
single-cache-miss inline compression branch in `ContentRouter`.
- Returned the original content with `PASSTHROUGH` and logged a
fail-open warning after the configured deadline, while preserving
under-deadline and deadline-disabled behavior.
- Added focused regressions for timeout, under-deadline output, and
disabled-deadline behavior, then kept the wider deadline suite green.
- Raised the locked production floors for `click` and `pillow` to clear
the current `pip-audit` findings that now fail external PR merge
snapshots.

## Testing

- [x] Unit tests pass (`uv run pytest
tests/test_content_router_single_item_deadline.py
tests/test_transforms/test_kompress_deadline.py -q`)
- [x] Linting passes (`uv run ruff check
headroom/transforms/content_router.py
tests/test_content_router_single_item_deadline.py
tests/test_transforms/test_kompress_deadline.py`)
- [ ] Type checking passes (`uv run mypy headroom`)
- [x] New tests added for new functionality
- [x] Manual testing performed

### Test Output

```text
uv run pytest tests/test_content_router_single_item_deadline.py tests/test_transforms/test_kompress_deadline.py -q

============================= test session starts =============================
platform win32 -- Python 3.12.13, pytest-9.0.3, pluggy-1.6.0
rootdir: D:\Repos\headroom-pr-2046-compression-freeze
configfile: pyproject.toml
plugins: anyio-4.12.1, langsmith-0.9.3, asyncio-1.3.0, cov-7.0.0
asyncio: mode=Mode.AUTO, debug=False, asyncio_default_fixture_loop_scope=None, asyncio_default_test_loop_scope=function
collected 5 items

tests\test_content_router_single_item_deadline.py ...                    [ 60%]
tests\test_transforms\test_kompress_deadline.py ..                       [100%]

============================== 5 passed in 0.42s ==============================

uv run ruff check headroom/transforms/content_router.py tests/test_content_router_single_item_deadline.py tests/test_transforms/test_kompress_deadline.py
All checks passed!

uv run ruff format headroom/transforms/content_router.py tests/test_content_router_single_item_deadline.py tests/test_transforms/test_kompress_deadline.py --check
3 files already formatted
```

## Real Behavior Proof

- Environment: Windows, Python 3.12.13, router-level harness with a
cooperative slow-compression stub
- Exact command / steps: `uv run pytest
tests/test_content_router_single_item_deadline.py
tests/test_transforms/test_kompress_deadline.py -q`, which forces one
frozen prefix and one cache miss, then sleeps past a 10 ms deadline
- Observed result: the guarded branch returns the original content
through `PASSTHROUGH` at the deadline, while under-deadline and
deadline-disabled behavior stay unchanged
- Not tested: native GIL-holding freeze

## 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
- [ ] 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
- [ ] I have updated the CHANGELOG.md if applicable

## Screenshots (if applicable)

Not applicable.

## Additional Notes

- Security CI currently flags `click 8.3.1` and `pillow 12.2.0`, so this
PR carries the narrow floor bump to `click>=8.3.3` and `pillow>=12.3.0`
as a supply-chain unblock for the same final merge snapshot.
- `CHANGELOG.md` remains untouched because Headroom generates release
notes from conventional commits.
- This PR is a Python-side mitigation for the single-cache-miss branch
only; the native GIL-hold root cause remains a separate owner.

---------

Co-authored-by: JerrettDavis <mxjerrett@gmail.com>
2026-07-13 23:50:49 -04:00
JD Davis
09be107d06
fix(deps): raise transformers security floor
Raise the production transformers floor to a version fixed for CVE-2026-5241 and refresh uv.lock so pip-audit passes.
2026-07-14 02:14:13 +00:00
GUOHAO LIU
8870b6971f
fix(deps): bump pillow to 12.3.0 and click to 8.4.2 (#2097)
## Description

Pip-audit found 6 vulnerabilities in 2 packages in the lockfile:

| Package | From | To | Vulns Fixed |
|---------|------|----|-------------|
| click | 8.3.1 | 8.4.2 | PYSEC-2026-2132 |
| pillow | 12.2.0 | 12.3.0 | PYSEC-2026-2253~2257 |

Closes #N/A (no issue filed — security workflow failure)

## Type of Change

- [x] Bug fix (non-breaking)
- [ ] New feature (non-breaking)
- [ ] Breaking change
- [ ] Documentation update

## Changes Made

- `uv.lock`: Upgraded click from 8.3.1 to 8.4.2, pillow from 12.2.0 to
12.3.0

## Testing

- [x] `uv lock --upgrade-package` resolved cleanly
- [x] `ruff check headroom/` passes
- [x] CLI import verified (click 8.4.2 loads correctly)

```
$ uv run python -c "import click; print(click.__version__)"
click: 8.4.2

$ uv tree --depth=1 | grep -E "click|pillow"
click v8.4.2
pillow v12.3.0 (extra: all)
pillow v12.3.0 (extra: image)
```

## Real Behavior Proof

- Environment: headroom main (upstream/main c365c7ff), uv-managed Python
3.12
- Exact command / steps: `uv lock --upgrade-package "pillow>=12.3.0"
--upgrade-package "click>=8.3.3"` on upstream/main; then `git diff
--stat`, `uv run python -c "import click; print(click.__version__)"`
- Observed result: uv.lock only changed; click 8.3.1 → 8.4.2, pillow
12.2.0 → 12.3.0; ruff passes; no test regressions
- Not tested: E2E proxy (dependency-only change — no code changes)

## Review Readiness

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

Co-authored-by: lennney <lennney@users.noreply.github.com>
2026-07-13 17:21:06 -05:00
石岳峰
4f3d5ab341
fix(install): add orjson to [proxy] extra for LiteLLM provider backends (#2074)
## Description
Add `orjson` to the `[proxy]` extra so `uv tool install
"headroom-ai[all]"` installs a runtime dependency required by LiteLLM
provider backends (e.g. OpenRouter).

## Type of Change
- [x] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation update

## Changes Made
- Add `orjson>=3.9.14; platform_python_implementation != 'PyPy'` to
`[proxy]`.
- Regression test in `tests/test_optional_dependencies.py`.
- Minimal `uv.lock` update (proxy/all optional-deps + metadata only).

## Motivation
Fixes #2056. `headroom-ai[all]` installs `litellm` (core dep) but not
`orjson`. LiteLLM provider backends import `orjson` at runtime; LiteLLM
only declares it under `litellm[proxy]`, not base deps. Headroom does
not depend on `litellm[proxy]` (would pull the full LiteLLM proxy server
stack).

## Testing
- `uv run --extra dev python -m pytest
tests/test_optional_dependencies.py -q` — 2 passed
- `uvx --from ruff==0.15.17 ruff check
tests/test_optional_dependencies.py`
- `uvx --from ruff==0.15.17 ruff format --check
tests/test_optional_dependencies.py`

## Real Behavior Proof
- **Setup:** Ubuntu, Python 3.12.3
- **Verified:** dependency graph test confirms `orjson` is selected for
`[proxy]` and `[all]` extras after this patch.
- **Not tested locally:** full `uv tool install` end-to-end (local sdist
build requires Rust/C++ toolchain unavailable in this environment).
Reporter workaround `uv tool install ... --with orjson` confirms the
missing transitive dep diagnosis.

## Review Readiness
- [x] I have performed a self-review of my code
- [x] This PR is ready for human review

## Notes
- Reporter used Python 3.14.4; `litellm` is intentionally skipped on
3.14 (GH #956). This PR fixes the missing `orjson` install path for
supported Python versions using `[all]`.

Co-authored-by: syf2211 <syf2211@users.noreply.github.com>
Co-authored-by: JerrettDavis <mxjerrett@gmail.com>
Co-authored-by: Tejas Chopra <chopratejas@gmail.com>
2026-07-13 09:37:28 -04:00
Ben Younes
fd0d29c92d
fix(packaging): guard torch extras on intel macos (#2011)
## Description

Closes #1931

Guard the `ml` and `voice` `torch` optional dependencies on macOS x86_64
so `headroom-ai[all]` remains resolvable on Intel Macs where PyTorch
does not publish compatible wheels for this version floor. The lockfile
metadata is updated with the same markers.

## Type of Change

- [x] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change that adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality to not work as expected)
- [ ] Documentation update
- [ ] Refactoring
- [ ] Performance improvement
- [ ] Test update
- [ ] Other

## Changes Made

- Added macOS x86_64 environment markers to `torch` in the `ml` and
`voice` extras.
- Updated `uv.lock` optional dependency metadata to match the guarded
extras.
- Added a packaging regression test that checks `[all]` keeps `ml` and
`voice` while guarding `torch` on macOS x86_64.

## Testing

- [x] Unit tests pass (`pytest`)
- [x] Linting passes (`ruff check`)
- [x] Formatting verified (`ruff format --check`)
- [ ] Manual testing performed

### Test Output

```text
$ python3 -m pytest tests/test_optional_dependencies.py -q
collected 1 item

tests/test_optional_dependencies.py .                                    [100%]

============================== 1 passed in 0.26s ===============================

$ .venv/bin/ruff check tests/test_optional_dependencies.py
All checks passed!

$ .venv/bin/ruff format --check tests/test_optional_dependencies.py pyproject.toml
1 file already formatted
```

## Test verification (RED -> GREEN)

RED, with the `torch` markers temporarily removed from `pyproject.toml`:

```text
tests/test_optional_dependencies.py F                                    [100%]
FAILED tests/test_optional_dependencies.py::test_all_extra_does_not_require_torch_on_macos_x86_64
E   assert False
```

GREEN, with this patch applied:

```text
tests/test_optional_dependencies.py .                                    [100%]
============================== 1 passed in 0.26s ===============================
```

## Real Behavior Proof

- Environment: Linux, Python 3.12.3, pytest 9.1.1, ruff 0.14.14.
- Exact command / steps: Removed the environment markers from `torch`,
ran the new packaging test, restored the markers, and reran the test
plus targeted ruff checks.
- Observed result: The test fails without the macOS x86_64 guard and
passes once the `ml` and `voice` `torch` requirements are guarded.
- Not tested: Full `uv run pytest`, full-project `uv run ruff check .`,
full-project `uv run ruff format --check .`, and `uv run mypy headroom`
were not run locally for this targeted packaging change.

## Review Readiness

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

## Checklist

- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [x] I have added tests that prove my fix is effective
- [x] New and existing targeted tests pass locally with my changes
- [x] Any dependent changes have been merged and published in downstream
modules

## Screenshots (if applicable)

N/A

## Additional Notes

No new dependency is added; this only narrows when the existing `torch`
optional dependency is selected.
2026-07-11 10:20:33 -05:00
OrbisAI Security
28ca61fc9d
fix: patch nltk vulnerability (CVE-2026-54293) (#1929)
## Description

Updates the locked `nltk` package from 3.9.4 to 3.10.0 to address
CVE-2026-54293, reported by OrbisAI Security as an information
disclosure/path traversal issue in `nltk.data.load()`.

Closes #

## 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

- Updated the `nltk` lockfile entry from 3.9.4 to 3.10.0.
- Added the new locked `defusedxml` dependency required by `nltk`
3.10.0.
- Added an explicit `nltk>=3.10.0` uv constraint so future lock
refreshes cannot regress below the fixed version.
- Updated the benchmark-extra comment now that the nltk CVE has an
upstream fixed release.

## Testing

<!-- Check what you actually ran, then paste the real command output
below. -->

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

### Test Output

```text
uv lock --locked
Resolved 257 packages in 1ms

uv run --extra benchmark python -c "import importlib.metadata as md; print('lm-eval', md.version('lm-eval')); print('rouge-score', md.version('rouge-score')); print('nltk', md.version('nltk'))"
lm-eval 0.4.10
rouge-score 0.1.2
nltk 3.10.0
```

## Real Behavior Proof

- Environment: GitHub pull request diff for
headroomlabs-ai/headroom#1929.
- Exact command / steps: Reviewed the PR diff and ran the focused uv
lock/import checks listed above.
- Observed result: The lockfile now points at nltk 3.10.0 artifacts,
includes the new defusedxml dependency, and records the nltk>=3.10.0
resolver constraint.
- Not tested: Full local test suite was not run for this lockfile-only
security update.

## 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
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] I have updated the CHANGELOG.md if applicable

## Screenshots (if applicable)

N/A.

## Additional Notes

Original automated security context from OrbisAI Security:

- CVE: CVE-2026-54293
- Severity: HIGH
- Scanner: trivy
- Rule: `CVE-2026-54293`
- File: `uv.lock`
- Assessment: Likely exploitable
- Description: nltk information disclosure via path traversal in
`nltk.data.load()`.

---------

Co-authored-by: JerrettDavis <mxjerrett@gmail.com>
2026-07-09 21:20:13 -07:00
Mohammad Hussian
662b7bc00e
fix(release): sync all package versions to v0.31.0 (#1882)
## Description

Current `main` has advanced the core package versions to `0.31.0`, but
the plugin marketplace manifests and hook plugin manifests were still
left at `0.30.0`. This PR now keeps the original version-sync intent
while updating the remaining metadata to the current release line.

It also preserves the previously-added `lxml-html-clean>=0.4.5` security
floor in `pyproject.toml` / `uv.lock` so the security audit remains
unblocked.

Closes #1872

## 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

- Synced `pyproject.toml`, SDK/package manifests, plugin manifests,
marketplaces, `.release-please-manifest.json`, and editable package lock
metadata to `0.31.0`.
- Updated the OpenClaw plugin dependency on `headroom-ai` to `^0.31.0`.
- Merged current `main` and resolved the version metadata conflicts in
favor of current `0.31.0` alignment.

## Testing

- [x] Unit tests pass (`pytest tests/test_plugin_manifests.py
scripts/tests/test_version_sync.py -q`)
- [ ] Linting passes (`ruff check .`)
- [ ] Type checking passes (`mypy headroom`)
- [ ] New tests added for new functionality
- [x] Manual testing performed (`python scripts/verify-versions.py`)

### Test Output

```text
python scripts/verify-versions.py
All versions aligned at 0.31.0

pytest tests/test_plugin_manifests.py scripts/tests/test_version_sync.py -q
10 passed in 0.42s
```

## Real Behavior Proof

- Environment: Windows, Python 3.13.13, PR head after merging current
`main`.
- Exact command / steps: Ran `python scripts/verify-versions.py` and
`pytest tests/test_plugin_manifests.py
scripts/tests/test_version_sync.py -q`.
- Observed result: Version verification exits successfully with `All
versions aligned at 0.31.0`; focused manifest/version-sync tests pass.
- Not tested: Full wheel/build matrix; this is metadata-only version
alignment and CI will cover the broader matrix.

## 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] My changes generate no new warnings
- [x] New and existing focused tests pass locally with my changes
- [ ] I have made corresponding changes to the documentation
- [ ] I have updated the CHANGELOG.md if applicable

---------

Co-authored-by: JerrettDavis <mxjerrett@gmail.com>
2026-07-09 16:53:55 -05:00
Tejas Chopra
0ba5065d40
Tejas/tool search deferral (#1885)
## Description

<!-- Briefly explain the change and why it is needed. -->

Closes #

## Type of Change

- [ ] 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

- 

## Testing

<!-- Check what you actually ran, then paste the real command output
below. -->

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

### Test Output

```text
# Paste relevant command output or artifact links here
```

## Real Behavior Proof

- Environment:
- Exact command / steps:
- Observed result:
- Not tested:

## Review Readiness

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

## Checklist

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

## Screenshots (if applicable)

Add screenshots to help explain your changes.

## Additional Notes

<!-- Mention any N/A checklist items, tradeoffs, follow-ups, or
maintainer context. -->

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-08 14:03:45 -07:00
dependabot[bot]
12060a6219
chore(deps): bump transformers from 5.0.0 to 5.3.0 in the uv group across 1 directory (#1662)
Bumps the uv group with 1 update in the / directory:
[transformers](https://github.com/huggingface/transformers).

Updates `transformers` from 5.0.0 to 5.3.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/huggingface/transformers/releases">transformers's
releases</a>.</em></p>
<blockquote>
<h2>v5.1.0: EXAONE-MoE, PP-DocLayoutV3, Youtu-LLM, GLM-OCR</h2>
<h2>New Model additions</h2>
<h3>EXAONE-MoE</h3>
<!-- raw HTML omitted -->
<p>K-EXAONE is a large-scale multilingual language model developed by LG
AI Research. Built using a Mixture-of-Experts architecture, K-EXAONE
features 236 billion total parameters, with 23 billion active during
inference. Performance evaluations across various benchmarks demonstrate
that K-EXAONE excels in reasoning, agentic capabilities, general
knowledge, multilingual understanding, and long-context processing.</p>
<ul>
<li>Add EXAONE-MoE implementations (<a
href="https://redirect.github.com/huggingface/transformers/issues/43080">#43080</a>)
by <a href="https://github.com/nuxlear"><code>@​nuxlear</code></a></li>
</ul>
<h3>PP-DocLayoutV3</h3>
<!-- raw HTML omitted -->
<p><strong>PP-DocLayoutV3</strong> is a unified and high-efficiency
model designed for comprehensive layout analysis. It addresses the
challenges of complex physical distortions—such as skewing, curving, and
adverse lighting—by integrating instance segmentation and reading order
prediction into a single, end-to-end framework.</p>
<ul>
<li>[Model] Add PP-DocLayoutV3 Model Support (<a
href="https://redirect.github.com/huggingface/transformers/issues/43098">#43098</a>)
by <a
href="https://github.com/zhang-prog"><code>@​zhang-prog</code></a></li>
</ul>
<h3>Youtu-LLM</h3>
<!-- raw HTML omitted -->
<p>Youtu-LLM is a new, small, yet powerful LLM, contains only 1.96B
parameters, supports 128k long context, and has native agentic talents.
On general evaluations, Youtu-LLM significantly outperforms SOTA LLMs of
similar size in terms of Commonsense, STEM, Coding and Long Context
capabilities; in agent-related testing, Youtu-LLM surpasses larger-sized
leaders and is truly capable of completing multiple end2end agent
tasks.</p>
<ul>
<li>Add Youtu-LLM model (<a
href="https://redirect.github.com/huggingface/transformers/issues/43166">#43166</a>)
by <a href="https://github.com/LuJunru"><code>@​LuJunru</code></a></li>
</ul>
<h3>GlmOcr</h3>
<!-- raw HTML omitted -->
<p>GLM-OCR is a multimodal OCR model for complex document understanding,
built on the GLM-V encoder–decoder architecture. It introduces
Multi-Token Prediction (MTP) loss and stable full-task reinforcement
learning to improve training efficiency, recognition accuracy, and
generalization. The model integrates the CogViT visual encoder
pre-trained on large-scale image–text data, a lightweight cross-modal
connector with efficient token downsampling, and a GLM-0.5B language
decoder. Combined with a two-stage pipeline of layout analysis and
parallel recognition based on PP-DocLayout-V3, GLM-OCR delivers robust
and high-quality OCR performance across diverse document layouts.</p>
<ul>
<li>[GLM-OCR] GLM-OCR Support (<a
href="https://redirect.github.com/huggingface/transformers/issues/43391">#43391</a>)by
<a
href="https://github.com/zRzRzRzRzRzRzR"><code>@​zRzRzRzRzRzRzR</code></a></li>
</ul>
<h2>Breaking changes</h2>
<ul>
<li>
<p>🚨 T5Gemma2 model structure (<a
href="https://redirect.github.com/huggingface/transformers/issues/43633">#43633</a>)
- Makes sure that the attn implementation is set to all sub-configs. The
config.encoder.text_config was not getting its attn set because we
aren't passing it to PreTrainedModel.<strong>init</strong>. We can't
change the model structure without breaking so I manually re-added a
call to self.adjust_attn_implemetation in modeling code</p>
</li>
<li>
<p>🚨 Generation cache preparation (<a
href="https://redirect.github.com/huggingface/transformers/issues/43679">#43679</a>)
- Refactors cache initialization in generation to ensure sliding window
configurations are now properly respected. Previously, some models (like
Afmoe) created caches without passing the model config, causing sliding
window limits to be ignored. This is breaking because models with
sliding window attention will now enforce their window size limits
during generation, which may change generation behavior or require
adjusting sequence lengths in existing code.</p>
</li>
<li>
<p>🚨 Delete duplicate code in backbone utils (<a
href="https://redirect.github.com/huggingface/transformers/issues/43323">#43323</a>)
- This PR cleans up backbone utilities. Specifically, we have currently
5 different config attr to decide which backbone to load, most of which
can be merged into one and seem redundant
After this PR, we'll have only one config.backbone_config as a single
source of truth. The models will load the backbone from_config and load
pretrained weights only if the checkpoint has any weights saved. The
overall idea is same as in other composite models. A few config
arguments are removed as a result.</p>
</li>
<li>
<p>🚨 Refactor DETR to updated standards (<a
href="https://redirect.github.com/huggingface/transformers/issues/41549">#41549</a>)
- standardizes the DETR model to be closer to other vision models in the
library.</p>
</li>
<li>
<p>🚨Fix floating-point precision in JanusImageProcessor resize (<a
href="https://redirect.github.com/huggingface/transformers/issues/43187">#43187</a>)
- replaces an <code>int()</code> with <code>round()</code>, expect light
numerical differences</p>
</li>
<li>
<p>🚨 Remove deprecated AnnotionFormat (<a
href="https://redirect.github.com/huggingface/transformers/issues/42983">#42983</a>)
- removes a missnamed class in favour of
<code>AnnotationFormat</code>.</p>
</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="aad13b87ed"><code>aad13b8</code></a>
v5.3.0</li>
<li><a
href="f6c63a6115"><code>f6c63a6</code></a>
protect imports (<a
href="https://redirect.github.com/huggingface/transformers/issues/44437">#44437</a>)</li>
<li><a
href="fd6bc380c8"><code>fd6bc38</code></a>
[vllm + v5 fix] handle TokenizersBackend fallback properly for v5 (<a
href="https://redirect.github.com/huggingface/transformers/issues/44255">#44255</a>)</li>
<li><a
href="30c480166a"><code>30c4801</code></a>
Fix CLI NameError: name 'TypeAdapter' is not defined (<a
href="https://redirect.github.com/huggingface/transformers/issues/44256">#44256</a>)</li>
<li><a
href="ee4c22078f"><code>ee4c220</code></a>
Enforce min length in some generate tests (<a
href="https://redirect.github.com/huggingface/transformers/issues/44401">#44401</a>)</li>
<li><a
href="a4f3df01aa"><code>a4f3df0</code></a>
[tiny] Add olmo_hybrid to tokenizer auto-mapping (<a
href="https://redirect.github.com/huggingface/transformers/issues/44416">#44416</a>)</li>
<li><a
href="1313588227"><code>1313588</code></a>
Update PR template (<a
href="https://redirect.github.com/huggingface/transformers/issues/44415">#44415</a>)</li>
<li><a
href="7235d44257"><code>7235d44</code></a>
Add eurobert (<a
href="https://redirect.github.com/huggingface/transformers/issues/39455">#39455</a>)</li>
<li><a
href="f60c4e9423"><code>f60c4e9</code></a>
Add Qwen3.5 support for sequence classification (<a
href="https://redirect.github.com/huggingface/transformers/issues/44406">#44406</a>)</li>
<li><a
href="fa7f4b68df"><code>fa7f4b6</code></a>
update the expected output for qwen2_5_vl w/ pytorch 2.10 XPU (<a
href="https://redirect.github.com/huggingface/transformers/issues/44426">#44426</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/huggingface/transformers/compare/v5.0.0...v5.3.0">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=transformers&package-manager=uv&previous-version=5.0.0&new-version=5.3.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions
You can disable automated security fix PRs for this repo from the
[Security Alerts
page](https://github.com/headroomlabs-ai/headroom/network/alerts).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-01 18:50:29 -05:00
Kenneth Wong
4db3bc91d9
fix(bedrock): add boto3 1.41 + CRT for aws login credentials (#1486)
## Description

`pip install headroom-ai[bedrock]` cannot serve users who authenticate
with `aws login` (IAM Identity Provider / console-login, DPoP).
Resolving those credentials requires the AWS Common Runtime (CRT);
without `awscrt`, botocore raises `MissingDependencyException`.

The AWS docs state the requirement as: **"Boto3 version 1.41.0 or later
with AWS Common Runtime (CRT)"** — i.e. both a modern boto3 floor and
CRT (installed via the `[crt]` extra).

## Type of Change

- [x] Bug fix (non-breaking)

## Changes Made

- `pyproject.toml` `bedrock` extra: bump `boto3>=1.28.0` →
`boto3>=1.41.0`, add `botocore[crt]>=1.41.0` (installs `awscrt`).
- `uv.lock`: regenerated — adds `awscrt`, resolves `boto3` to 1.42.x.

No code changes — the bedrock backend already passes `aws_profile_name`
through to the LiteLLM calls (via #1456); this just makes the installed
dependencies actually able to resolve `aws login` credentials.

## Impact

- **`aws login` (IAM Identity Provider / DPoP):** now works — awscrt
present.
- **`aws sso login` (classic Identity Center):** unaffected (already
worked).
- **static keys (`~/.aws/credentials`):** unaffected.
- Bumping the boto3 floor only affects the optional `[bedrock]` extra;
bedrock users benefit from a current boto3 regardless.

## Testing

Dependency-only change. `uv lock` resolves cleanly (257 packages, awscrt
0.29.2, boto3 1.42.38). No runtime code path altered, so existing
bedrock tests are unaffected.

## Checklist

- [x] Self-review performed
- [x] No new warnings
- [x] Linting passes

## Additional Notes

Focused on the dependency gap only. ARN routing / named-profile wiring /
docs are handled in #1456; pricing in #1485.
2026-06-28 14:51:52 -07:00
Tejas Chopra
5771a8020e
fix(deps): remediate dependency CVEs and publish SBOM (#1509)
## Description

Supply-chain hardening: takes the **shipped** dependency surface from
**26 known CVEs to 0**. `pip install headroom-ai[all]` now resolves with
no known vulnerabilities (verified with Anchore syft + grype). Also
publishes a checked-in SBOM package (`sbom/`) so any user — especially
pilots running their own security review — can verify what's inside and
that we track it.

This addresses the Dependabot alerts on `main` (9 high / 4 moderate / 7
low at time of writing).

Closes #

## 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)
- [x] Documentation update
- [ ] Performance improvement
- [ ] Code refactoring (no functional changes)

## Changes Made

**Rust**
- `pyo3` 0.24 → 0.29 (GHSA-36hh-v3qg-5jq4 High, GHSA-chgr-c6px-7xpp
Med). Migrated `Python::allow_threads` → `Python::detach` (10 sites) and
added `from_py_object` to the `Clone`-deriving `#[pyclass]` types (both
required by the 0.25+ API).
- `pyo3-log` 0.12 → 0.13; `lru` 0.12 → 0.18 (GHSA-rhfx-m35p-ff5j).

**Python**
- `torch` → 2.12.1, `mem0ai` → 2.x.
- Floor-pinned transitive CVE deps via `[tool.uv]
constraint-dependencies`: `pygments>=2.20.0`,
`pydantic-settings>=2.14.2`, `gitpython>=3.1.50`, `langsmith>=0.9.0`.
- **Removed `benchmark` from the `[all]` aggregate** so the default
install is CVE-free. `lm-eval` is invoked as an external subprocess
(`python -m lm_eval`) and never imported, so it is not a true runtime
dep — it remains available via the opt-in `[benchmark]` extra. See
[Accepted Risks](#additional-notes).

**npm (build/test tooling — never shipped in the
wheel/container/published SDK)**
- `esbuild` override `>=0.28.1` in `sdk/typescript` + `plugins/openclaw`
(GHSA-g7r4-m6w7-qqqr).
- `docs/`: `@anthropic-ai/sdk` → `^0.106.0` (GHSA-p7fg-763f-g4gf),
`postcss` override to force Next.js's bundled copy ≥8.5.10
(GHSA-qx2v-qp2m-jg93); regenerated a stale `bun.lock` that carried a
**Critical** vitest/vite.

**CI**
- Pinned `pypa/gh-action-pypi-publish` `@release/v1` → `@v1.13.0`
(GHSA-vxmw-7h4f-hqxh) in `release.yml` + `publish.yml`.

**SBOM**
- New `sbom/` directory: CycloneDX 1.7 + SPDX 2.3 SBOMs, grype scan
evidence, 330-package license inventory, and a regeneration guide.

## Testing

- [ ] Unit tests pass (`pytest`) — N/A, no Python source changed
(deps/config only)
- [x] Linting passes — `cargo fmt --check` + `cargo clippy` clean on the
changed crate; 0 `.py` files changed so `ruff`/`mypy` scope is
unaffected
- [x] Type checking passes — `cargo check --workspace` (0 errors)
- [ ] New tests added — N/A (dependency bumps; covered by existing
suites)
- [x] Manual testing performed — see Real Behavior Proof

### Test Output

```text
# headroom-ai[all] product surface — the number that matters
$ grype sbom:sbom/headroom-sbom-all-extra.cdx.json
No vulnerabilities found

# full repo scan (universal lock incl. opt-in [benchmark] + dev)
$ grype sbom:sbom/headroom-sbom.cdx.json
NAME        INSTALLED  TYPE    VULNERABILITY        SEVERITY
sqlitedict  2.1.0      python  GHSA-g4r7-86gm-pgqc  High      # [benchmark]-only, unpatchable, accepted
nltk        3.9.4      python  GHSA-p4gq-832x-fm9v  High      # [benchmark]-only, unpatchable, accepted

# pyo3 0.29 migration — extension builds + imports + runs
$ cargo check --workspace
    Finished `dev` profile [unoptimized + debuginfo] target(s)
$ maturin develop && python -c "from headroom._core import DiffCompressor, SmartCrusher; ..."
extension OK — detach + from_py_object paths exercised

# lru 0.18 — eviction path
$ cargo test -p headroom-proxy --lib drift
14 passed, 213 filtered out

# per-ecosystem npm audits
$ (cd sdk/typescript && npm audit)         -> found 0 vulnerabilities
$ (cd plugins/openclaw && npm audit)       -> found 0 vulnerabilities
$ (cd docs && npm audit && bun audit)      -> found 0 vulnerabilities / No vulnerabilities found
```

## Real Behavior Proof

- Environment: macOS (darwin 25.4.0, arm64), Python 3.12 `.venv`, Rust
1.95 toolchain, syft 1.46.0, grype 0.115.0, bun 1.3.14, maturin 1.13.3.
- Exact command / steps: (1) `uv export --extra all --no-dev
--no-emit-project | syft → grype` for the product surface; (2) `cargo
check --workspace` + `maturin develop` + extension import/compress smoke
test; (3) `cargo test -p headroom-proxy --lib drift`; (4) `cargo fmt
--check` + `cargo clippy -p headroom-py`; (5) `npm audit` in
sdk/openclaw/docs + `bun audit` in docs.
- Observed result: `headroom-ai[all]` resolution scans clean — "No
vulnerabilities found" (179 pkgs); full/prod SBOM shows only the 2
documented accepted CVEs; pyo3 0.29 extension imports and runs (detach +
from_py_object paths exercised); drift tests 14/14 pass; cargo fmt +
clippy clean; all npm/bun audits report 0.
- Not tested: full `pytest` suite (no Python source changed);
release-profile wheel build (used dev-profile `maturin develop` for the
import proof — the extension is semantically identical).

## 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
(`sbom/README.md`)
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective — N/A
(dependency bumps; existing suites + scans cover it)
- [x] New and existing unit tests pass locally with my changes
- [ ] I have updated the CHANGELOG.md — N/A (Release Please
auto-generates from the conventional commit)

## Additional Notes

**Accepted risks (the 2 residual CVEs).** Both originate solely from the
EleutherAI `lm-evaluation-harness` under the **opt-in `[benchmark]`
extra**, which Headroom invokes as a subprocess (never imports):
- `sqlitedict` CVE-2024-35515 (High) — pickle deserialization; package
abandoned (last release 2021), **no upstream fix exists**.
- `nltk` CVE-2026-54293 (High) — path traversal in `nltk.data.load()`;
affects ≤3.9.4 (current latest), **no patched release**.

Neither is in `[all]`, the published wheel, or the container. They are
documented in `sbom/README.md` and will be picked up automatically once
upstream ships fixes.

**Release/CHANGELOG:** N/A items above are because this is a
dependency/security PR with no Python source changes; CHANGELOG is
Release-Please-managed via the conventional commit message.
2026-06-27 15:28:12 -07:00
Lucas Santos
35939c3536
fix(dashboard): include RTK stats in the historical tab (#1324)
## Description

Restart the proxy, open the dashboard, go to the Historical tab and the
RTK stats are gone. The Session tab shows them fine, Historical just
doesn't have them.

The reason is where the two tabs get their numbers. The Session tab
calls `_get_context_tool_stats()` live, which reads RTK's own stats
file. The Historical tab calls `history_response()`, which only contains
the persisted proxy-compression data. RTK savings are never written into
that savings JSON, they live in the RTK tool's separate stats file, so
after a restart Historical has nothing to show for them.

The fix makes `/stats-history` do the same thing `/stats` already does:
pull the live RTK stats with `_get_context_tool_stats()` and attach them
to the history response under a `cli_filtering` key (with `tool`,
`label`, `lifetime` and `session`). The Historical tab then renders an
RTK card from `historyStats.cli_filtering.lifetime.tokens_saved`.

A few notes:

1. The card is hidden when `cli_filtering` is null, so setups without
RTK look exactly as they do today. No empty card, no errors.
2. Reading the RTK stats is best-effort: if `_get_context_tool_stats()`
raises (missing file, parse error, IO), `cli_filtering` falls back to
null and the Historical tab stays available rather than returning a 500.
3. Nothing about how RTK stats are stored changed, we just read them on
the history endpoint too, so there's no migration.

Closes #1177

## 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

- `headroom/proxy/server.py`: the `/stats-history` handler now attaches
live RTK stats under `cli_filtering`, the same source `/stats` uses,
wrapped in best-effort error handling; the endpoint docstring documents
the curated shape.
- `headroom/dashboard/templates/dashboard.html`: add an RTK card to the
Historical tab, hidden when there's no RTK data.
- `tests/test_proxy_savings_history.py`:
`test_stats_history_includes_cli_filtering`.

## Testing

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

### Test Output

```text
$ uv run --extra dev python -m pytest tests/test_proxy_savings_history.py -q
passed
ruff: All checks passed!
mypy: Success: no issues found
```

## Real Behavior Proof

- Environment: macOS, Python 3.13, this branch.
- Exact command / steps: `uv run --extra dev python -m pytest
tests/test_proxy_savings_history.py::test_stats_history_includes_cli_filtering`.
The test hits `/stats-history` and asserts the payload carries
`cli_filtering` with the RTK numbers the Historical tab reads.
- Observed result: the `/stats-history` response now carries
`cli_filtering` (`tool`/`label`/`lifetime`/`session`), the field the
Historical tab was missing after a restart. `ruff` and `mypy` are clean
on the changed files.
- Not tested: I did not click through the rendered dashboard after a
real restart, and this repo's test suite needs the native `_core`
extension built (CI builds it), so the assertion runs in CI. The data
the tab consumes is covered by the test, and the card is gated on that
data being present.

## 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
- [ ] 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 have updated the CHANGELOG.md if applicable

## Additional Notes
2026-06-25 07:55:36 -07:00
Rudimar Ronsoni
b4571cc346
feat: headroom wrap opencode / unwrap opencode CLI (#1105)
## Summary

This PR implements transparent `headroom wrap opencode` support without
asking users to edit OpenCode provider URLs, choose an extra CLI flag,
or maintain a static provider list.

The wrapper now lives at the runtime transport boundary: OpenCode keeps
its user/provider config, while Headroom intercepts outbound provider
traffic in-process and routes it through the local Headroom proxy.

## What changed

### Transparent OpenCode wrapping

- `headroom wrap opencode` injects the `headroom-opencode` plugin
through `OPENCODE_CONFIG_CONTENT`.
- Existing OpenCode provider URLs are preserved. We do not rewrite user
config URLs to point at Headroom.
- Existing `OPENAI_BASE_URL` and `ANTHROPIC_BASE_URL` env vars are
preserved.
- Local OpenCode traffic, localhost traffic, and Headroom proxy traffic
bypass the shim to avoid loops.

### Runtime transport interception

- Added an OpenCode plugin transport shim that wraps:
  - `globalThis.fetch`
  - `http.request` / `http.get`
  - `https.request` / `https.get`
- External provider calls are routed to the local Headroom proxy.
- The original upstream origin is passed through `x-headroom-base-url`,
so the proxy can forward to the real provider without changing OpenCode
config.
- External `http2.connect` is blocked loudly instead of allowing direct
provider traffic to leak outside Headroom.

### Live provider additions

Provider coverage is no longer based on a static config scan. Because
routing happens at outbound request time, providers added mid-session
are routed through Headroom automatically as long as they use the
covered Node transport paths.

### Subagent and child-process coverage

- The parent OpenCode plugin sets a packaged Node preload shim through
`NODE_OPTIONS=--import=.../hook-shim/handler.js`.
- The transport shim patches `child_process.spawn`, `exec`, `execFile`,
and `fork` so child Node processes receive the Headroom preload even
when OpenCode passes a custom `env`.
- The child-process shim fails closed if it loads without
`HEADROOM_OPENCODE_TRANSPORT_PROXY_URL`.
- This closes the subagent leak path where a child Node process could
otherwise start without Headroom transport interception.

## Why this goes beyond PR #1089

PR #1089 improves OpenCode provider registration, but it still focuses
on provider config shape. This PR moves the enforcement boundary to
runtime transport interception.

This PR goes further because:

- No provider URL rewriting is required.
- New providers added mid-session are covered automatically.
- Subagents and child Node processes inherit the Headroom transport
shim.
- Direct external HTTP/2 paths fail loudly instead of leaking.
- The wrap remains transparent to the user's OpenCode provider config.
- The wrapper is fail-closed for unsupported child-process preload
state.

## Additional robustness fixes

While validating the change in Docker, the full Python suite exposed
unrelated Linux/container robustness issues. These are fixed in this PR
so the suite is green:

- Binary cache handling now treats cache paths under a non-writable
existing parent as unavailable, including when tests run as root in
Docker.
- `release_version.py` honors `MANUAL_VER` before git calls so direct
script execution works outside a `.git` checkout.
- Test logger isolation now resets relevant Headroom child loggers so
proxy logging setup cannot poison later `caplog` tests.
- The scanner missing-path test now uses a guaranteed missing `tmp_path`
child instead of relying on `/nonexistent/path`.

## Validation

All implementation validation was run inside Docker.

- Full Python suite from a fresh Docker copy: `6605 passed, 523
skipped`.
- Ruff on changed Python/OpenCode paths: passed.
- OpenCode plugin typecheck: passed.
- OpenCode plugin tests: `9 passed`.
- OpenCode plugin build: passed.
- Hook shim preload smoke test: passed.

## Notes

This PR intentionally does not add a CLI option. `headroom wrap
opencode` means full wrap. Either Headroom wraps OpenCode transparently,
or the path fails loudly instead of silently leaking provider traffic.

---------

Co-authored-by: Rudimar Ronsoni <6081613+rudironsoni@users.noreply.github.com>
2026-06-22 11:07:12 -05:00
dependabot[bot]
c65e321ea2
ci: bump the uv group across 1 directory with 5 updates (#1020)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions
You can disable automated security fix PRs for this repo from the
[Security Alerts
page](https://github.com/chopratejas/headroom/network/alerts).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-16 15:02:41 -05:00
dependabot[bot]
27befef694
ci: bump the uv group across 1 directory with 17 updates (#832)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions
You can disable automated security fix PRs for this repo from the
[Security Alerts
page](https://github.com/chopratejas/headroom/network/alerts).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-10 18:20:43 -05:00
Patrick A
9579567b7d
chore(deps): loosen over-pinned constraints and add upper bounds (#538)
## What

Loosen over-pinned Python dependency constraints and add missing upper
bounds in `pyproject.toml`. Also bump the neo4j Docker image and uv
builder version.

## Why

Several dependencies had constraints that either blocked security
patches or allowed silent major-version jumps:

- `litellm==1.82.3` was an exact pin — every security patch release
requires a manual lockfile bump
- `transformers`, `sentence-transformers` had no upper bound and have
already crossed major version boundaries without a constraint gate
- `neo4j>=5.20.0` had no upper cap; the driver has already reached 6.x
in the wild
- `mem0ai>=0.1.100` had a pre-1.0 floor while the locked version is
already 1.0.11
- `langchain-core`, `langchain-openai`, `qdrant-client`, `uvicorn` had
no upper bound on a range with active major-version churn
- `docker-compose.yml` pinned neo4j at `5.15.0`, which is 11 patch
releases behind the current 5.x LTS
- `Dockerfile` pinned uv at `0.11.16`; latest stable is `0.11.18`

## How

Constraint changes only — no code changes, no `uv lock --upgrade`. The
existing locked versions all satisfy the new bounds (we added caps, not
floors). `uv` re-resolved the lockfile to format revision 3 (adds
`upload-time` metadata fields) and cleaned up the defunct `llmlingua`
extra entries.

| Dependency | Before | After |
|---|---|---|
| `litellm` | `==1.82.3` | `>=1.82.3,<2.0` |
| `transformers` | `>=4.30.0` | `>=4.30.0,<6.0` |
| `sentence-transformers` | `>=2.2.0` | `>=2.2.0,<6.0` |
| `neo4j` | `>=5.20.0` | `>=5.20.0,<7.0` |
| `mem0ai` | `>=0.1.100` | `>=1.0.0,<2.0` |
| `langchain-core` | `>=0.2.0` | `>=0.2.0,<4.0` |
| `langchain-openai` | `>=0.1.0` | `>=0.1.0,<2.0` |
| `qdrant-client` | `>=1.9.0` | `>=1.9.0,<2.0` |
| `uvicorn` | `>=0.23.0` | `>=0.23.0,<1.0` |
| neo4j Docker image | `5.15.0` | `5.26` |
| uv (Dockerfile ARG) | `0.11.16` | `0.11.18` |

## Breaking changes

None. All currently installed versions fall within the new ranges.
Installers that previously resolved `litellm` to an older exact pin may
now resolve newer patch releases — which is the desired behavior.

---------

Co-authored-by: Tejas Chopra <chopratejas@gmail.com>
2026-06-08 22:06:24 -08:00
Patrick A
fa558c5647
fix(deps): move gunicorn to [proxy-prod] extra, add Windows guard (#537)
* fix(deps): add missing runtime deps to [code] and [proxy] extras

- Add gunicorn>=21.0.0 to the [proxy] extra

The proxy docs (docs/content/docs/proxy.mdx and wiki/proxy.md) show
gunicorn as the recommended production deployment server:

  pip install gunicorn
  gunicorn headroom.proxy.server:app --worker-class uvicorn.workers.UvicornWorker

Users installing headroom-ai[proxy] for production get uvicorn (already
declared) but had to discover and install gunicorn manually. Adding it
to [proxy] removes that friction.

Investigation notes:
- [code] only needs tree-sitter-language-pack (already declared).
  code_compressor.py has zero numpy imports. The kompress fallback
  inside code_compressor.py is guarded by ImportError and requires [ml].
- numpy is correctly declared in [relevance] (numpy>=1.24.0) and pulled
  transitively by sentence-transformers in [memory]. It is NOT needed
  under [code].
- tree-sitter is a transitive dep of tree-sitter-language-pack (requires
  tree-sitter>=0.25.2) so it does not need an explicit entry.

* docs(changelog): add entry for gunicorn proxy dep fix

style(tests): ruff format test_provider_proxy_routes.py (blank lines after docstrings)

* fix(deps): move gunicorn to [proxy-prod] extra, add Windows guard

- Remove gunicorn from [proxy] so dev, CI, and Windows users are not
  forced to install a Unix-only package that does nothing on Windows
- Add new [proxy-prod] extra that includes [proxy] + gunicorn with a
  sys_platform != 'win32' environment marker
- Production users: pip install 'headroom-ai[proxy,proxy-prod]'
- Update CHANGELOG to reflect the new extra name

* fix(devcontainer): bump uv floor to >=0.11.0 for lockfile compatibility

uv 0.6.17 (previously pinned) cannot parse lockfiles generated by
uv >= 0.11.x. The validate CI job (triggered by pyproject.toml
changes) was failing with 'Failed to parse uv.lock'. Loosening the
pin to >=0.11.0 picks up the matching format parser while keeping the
Docker layer cacheable with a range rather than an exact pin.

* fix(devcontainer): skip gitpython wheel filename check in uv sync

gitpython 3.1.47 on PyPI has wheel gitpython-3.1.46-py3-none-any.whl
(wrong filename). uv >=0.11.19 strict filename validation rejects this
lockfile entry. UV_SKIP_WHEEL_FILENAME_CHECK=1 bypasses the check until
the upstream lockfile is regenerated with a corrected entry.

* fix(deps): correct gitpython version in uv.lock to match actual wheel

gitpython 3.1.47 on PyPI was uploaded with sdist/wheel files named
gitpython-3.1.46.*. The version field in uv.lock said 3.1.47 but all
download URLs reference 3.1.46 files, causing uv >=0.11.19 to refuse
to parse the lockfile with a version-mismatch error.

Change the version field to 3.1.46 so the entry is internally
consistent. Also revert the now-unnecessary UV_SKIP_WHEEL_FILENAME_CHECK
workaround from post-create.sh.

---------

Co-authored-by: Tejas Chopra <chopratejas@gmail.com>
2026-06-07 23:49:14 -07:00
Steven Cuz Leath
07581b9e80 Fix: Upgrade litellm to 1.86.2 to remediate CVE-2026-42271 2026-06-01 09:57:39 +00:00
chopratejas
e325d1b866 fix(ci): pin public PyPI in pyproject.toml + scrub Netflix URLs from uv.lock
Devcontainer validate jobs were failing on PR #360 with:

    × Failed to fetch:
      https://pypi.netflix.net/packages/.../nvidia_nvshmem_cu12-3.4.5-...whl
    ├─▶ Request failed after 3 retries
    ╰─▶ operation timed out

`pypi.netflix.net` is Netflix's internal PyPI mirror. It got into the
lockfile because my local `~/.config/uv/uv.toml` had:

    index-url = "https://pypi.netflix.net/simple"

Running `uv lock` from that machine baked Netflix-internal URLs into
uv.lock for every package. Public CI runners (and any external
contributor) can't resolve them.

Two fixes:

1. Add `[[tool.uv.index]]` block to pyproject.toml pinning public PyPI
   as the project's default index. uv now ignores user-level config when
   resolving for this project, regardless of who runs `uv lock`. This
   prevents the same contamination from any developer in the future.

2. Regenerate uv.lock against public PyPI. All package URLs now point
   at `https://files.pythonhosted.org/...` and `https://pypi.org/simple/`.
   Zero references to `pypi.netflix.net` remain in the lockfile.

Verified: `grep -c "pypi.netflix" uv.lock` returns 0.
2026-05-03 13:52:16 -07:00
chopratejas
2a91cbb4b4 refactor: single-wheel maturin build backend (fixes #355)
Eliminates the dual-package architecture that was the root cause of #355.
`pip install headroom-ai` now produces ONE wheel containing both the Python
source (headroom/*.py) and the compiled Rust extension (headroom/_core.so).
No more separate `headroom-core-py` package, no more chicken-and-egg with
PyPI publication, no more wheelhouse / PIP_FIND_LINKS / composite-action
plumbing in CI.

This is the canonical pattern used by cryptography, polars, ruff,
pydantic-core, and other Rust-as-core Python packages. Honors the
"Rust as core engine" direction.

## What changed

- pyproject.toml: `[build-system]` swapped from hatchling to maturin.
  `[tool.hatch.*]` deleted; `[tool.maturin]` added pointing at
  `crates/headroom-py/Cargo.toml` for the cdylib. `python-source = "."`
  picks up the root `headroom/` package directly (dashboard HTML
  templates and other non-Python files included automatically).
- crates/headroom-py/pyproject.toml: deleted. The crate is no longer a
  separate published package; its Cargo.toml stays as the cdylib build
  target invoked via `[tool.maturin] manifest-path`.
- crates/headroom-py/python/: deleted (placeholder layout for the old
  separate package).

## CI updates

- ci.yml: `test` / `test-extras` / `test-agno` jobs simplified — Rust
  toolchain set up before `pip install -e .` (which now invokes maturin
  via build-system). Removed the "build wheel + symlink .so" dance.
  `build` job swapped from `python -m build` (hatch) to
  `maturin build` + `maturin sdist`.
- release.yml: collapsed dual-package matrix into one. New `build-wheels`
  matrix produces cross-platform wheels for cp310/11/12/13 ×
  {linux x86_64, linux aarch64, macos x86_64, macos aarch64}. New
  `collect-dist` aggregator merges artifacts. publish-pypi consumes the
  merged dist.
- init-native-e2e.yml: dropped windows-latest from the matrix —
  upstream `esaxx-rs` (/MT) and `ort-sys` (/MD) link with conflicting
  MSVC C runtime libraries, so the Rust extension cannot build for
  win_amd64 today. Tracked as a follow-up; not a blocker for Linux+macOS.
- headroom-e2e-setup: composite action now sets up Rust toolchain +
  Swatinem/rust-cache before `pip install -e .[proxy]`.
- eval.yml, publish.yml, rust.yml: same pattern — rust toolchain before
  install. rust.yml's wheels job builds from root pyproject.toml (no
  more `-m crates/headroom-py/Cargo.toml`).
- e2e/init/Dockerfile, e2e/wrap/Dockerfile: install rust + maturin in
  the build stage; copy `crates/` + workspace `Cargo.toml/lock` so the
  install can build the extension. Dropped `HEADROOM_REQUIRE_RUST_CORE=false`
  from wrap-e2e — the image now ships the full Rust core.
- Dockerfile (main): simplified — no more Layer 2/3 dance with
  `headroom-core-py` install + symlink. Single `uv pip install` builds
  + installs everything.
- .devcontainer/Dockerfile: rust toolchain + libssl-dev + maturin
  added so `uv sync` builds the extension inside the devcontainer.

## Lockfile + script

- uv.lock: regenerated. No `headroom-core-py` entries remain.
- scripts/build_rust_extension.sh: simplified from a symlink-into-tree
  workaround to a thin wrapper around `pip install -e .`. The maturin
  build-backend handles placement automatically.

## Local validation (all green on macOS aarch64)

1. Clean venv `pip install -e .` → `from headroom._core import …` works.
2. `maturin build --release` → 13.8 MB wheel, 336 files including
   `headroom/_core.cpython-311-darwin.so` (32 MB cdylib) and
   `headroom/dashboard/templates/dashboard.html`.
3. `pip install <wheel>` in fresh venv → import works.
4. Wheel contents verified via `unzip -l`.
5. `pytest tests/test_transforms/test_diff_compressor.py` — 29 passed.
6. `pytest tests/test_relevance.py` — 30 passed.
7. `cargo build --workspace` + `cargo test --workspace` — all green.
8. `make ci-precheck` — 176 Python tests + Rust + commitlint green.

## Migration notes

Users on `pip install headroom-ai` get the Rust core automatically
(linux + macos wheels). sdist installs require rust toolchain available
locally — pip will build via maturin.

Closes #355
Supersedes #357 (workarounds-based fix abandoned in favor of
architectural fix)
2026-05-03 13:16:41 -07:00
chopratejas
ce3b2f0b0b fix(ci): regenerate uv.lock against public PyPI (was Netflix-internal)
The validate × 3 devcontainer CI failures were NOT environmental —
they were caused by this branch.

Root cause: commit 967b0db (PR-B1 big delete) was made on a Netflix
machine where uv was configured to use the internal mirror. The
subagent ran `uv lock` to regenerate after deleting deps, capturing
`pypi.netflix.net/simple` as the registry for every package and
`pypi.netflix.net/packages/<id>/<file>.whl` as the URL for every
wheel and sdist. main's lock points at public `pypi.org/simple` and
`files.pythonhosted.org/packages/...`.

When CI ran on GitHub Actions runners (no Netflix network access),
uv tried to fetch from `pypi.netflix.net` and timed out — surfacing
as "Failed to download cuda-bindings==12.9.4 / safetensors==0.7.0
/ nvidia-cuda-cupti-cu12==12.8.90 — request failed after 3 retries".
Devs running the same devcontainer locally on a Netflix machine
saw it work because their box could reach the internal mirror.

Fix: restore main's uv.lock and regenerate against public PyPI:
    UV_INDEX_URL=https://pypi.org/simple \
    UV_DEFAULT_INDEX=https://pypi.org/simple \
    uv lock

The regenerated lock has 311 pypi.org URLs and 0 pypi.netflix.net
URLs. The pytest `live` marker added in Wave 3 was the only real
pyproject.toml change in the branch — no dep deltas — so the lock's
package set matches what main resolves modulo a handful of
transitive bumps (loguru, mmh3, py-rust-stemmers, win32-setctime,
pillow 11.3.0).

This is the correct lock for upstream CI. Anyone working on a
Netflix box should rely on uv's index-URL override at install time
(or pin via UV_INDEX_URL in their shell), NOT bake the internal
mirror into the canonical lockfile that ships in the repo.
2026-05-02 20:00:44 -07:00
chopratejas
967b0db439 fix: B1 — retire ICM, RollingWindow, scoring, relevance + dependents
Phase B step 1 of the live-zone-only realignment. Removes ~10K LOC of
"drop messages from history" machinery that became unreachable after
PR-A1 made `/v1/messages` a passthrough on the proxy. Live-zone-only
compression (PR-B2..B7) operates on content blocks within messages;
message-list mutation no longer happens in the pipeline.

Python deletes:
- headroom/transforms/intelligent_context.py (1077 LOC)
- headroom/transforms/rolling_window.py (395 LOC)
- headroom/transforms/progressive_summarizer.py (508 LOC)
- headroom/transforms/scoring.py (459 LOC)
- headroom/transforms/tool_crusher.py (338 LOC)
- 5 corresponding tests/test_transforms/* and tests/test_proxy_intelligent_context.py

Rust deletes:
- crates/headroom-core/src/context/* (manager, config, workspace,
  candidate, ccr_drop, strategy/, mod) + safety.rs replaced
- crates/headroom-core/src/scoring/* (mod, score, scorer, traits, weights)
- MessageScorerComparator from crates/headroom-parity (PR #338/#343
  becomes deletable; sunk cost stays sunk)
- 13 message_scorer fixtures + record_message_scorer.py

Rust adds (move + rewrite):
- crates/headroom-core/src/transforms/safety.rs — `tool_pair_indices`
  preserves the OpenAI/Anthropic tool_use ↔ tool_result pairing rule
  the live-zone dispatcher (PR-B2) needs. No IcmConfig dependency.

Surface refactors:
- HeadroomConfig: drop `tool_crusher`, `rolling_window`,
  `intelligent_context` fields; hoist `output_buffer_tokens` to top
  level (used by client.py).
- ProxyConfig: drop `intelligent_context*` fields.
- `headroom wrap` proxy server: retire IntelligentContextManager
  and RollingWindow imports + branch; pipeline is CacheAligner →
  ContentRouter (smart_routing) or CacheAligner → SmartCrusher
  (legacy).
- CLI: drop `--no-intelligent-context`, `--no-intelligent-scoring`,
  `--no-compress-first` flags.
- LangChain memory integration: rename `_apply_rolling_window` →
  `_apply_compression`, drop RollingWindowConfig dep. Threshold is
  now advisory — B6 will rework the contract.
- TransformPipeline.create_pipeline now takes only cache_aligner_config.
- headroom/__init__.py + headroom/transforms/__init__.py: strip
  exports of deleted symbols.

Bug fixes uncovered by full pytest sweep:
- providers/copilot/wrap.py: `environ or os.environ` collapsed
  empty-dict to falsy → callers passing `environ={}` accidentally
  pulled from os.environ. Use `environ if environ is not None else
  os.environ`.

Test correctness fixes:
- _DummyAnthropicHandler._retry_request gains **_kwargs to match
  the real handler signature post-A8.
- test_ws_http_fallback extracts JSON from `content=` (post-A3
  byte-faithful) rather than the obsolete `json=` kwarg.
- test_ccr_response_handler_extra fixture joins SSE events with
  `\n\n` per spec (post-A8 byte-buffer parser requirement).
- test_proxy_responses_phase_preservation: capture via direct
  handler attached to the named logger, so the assertion is
  order-independent (proxy `_setup_file_logging` flips
  `headroom.propagate=False` once any earlier test triggers it).
- conftest.py autouse fixture resets `headroom.propagate=True`
  before each test as a defensive measure for the same pollution.
- test_wrap_copilot_translated_backend_still_requires_byok:
  monkeypatch.delenv every provider key so the BYOK error
  actually fires.
- test_native_installers: skip when system bash < 4.3 (macOS ships 3.2).
- TestGeminiEmbedContent / TestGeminiBatchEmbedContents:
  pytest.mark.skip — proxy currently has no :embedContent route;
  feature gap, not regression.

Acceptance:
- cargo build --workspace + cargo clippy + cargo fmt --check: green.
- cargo test --workspace --exclude headroom-py: 777 passed.
- pytest: 4892 passed, 240 skipped, 0 failed.
- git grep returns only intentional comments referencing the deletion.

Per-PR-B1 plan: REALIGNMENT/04-phase-B-live-zone.md.
2026-05-02 12:23:17 -07:00
dependabot[bot]
e25f5515ab
chore(deps): bump nltk in the uv group across 1 directory
Bumps the uv group with 1 update in the / directory: [nltk](https://github.com/nltk/nltk).


Updates `nltk` from 3.9.2 to 3.9.4
- [Changelog](https://github.com/nltk/nltk/blob/develop/ChangeLog)
- [Commits](https://github.com/nltk/nltk/compare/3.9.2...3.9.4)

---
updated-dependencies:
- dependency-name: nltk
  dependency-version: 3.9.4
  dependency-type: indirect
  dependency-group: uv
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-23 16:15:12 +00:00
Adryan Eka Vandra
b71b659e1b
fix(ci): restore repro harness test in dev installs
Add websockets to the dev extra so the repro harness smoke test can import
its websocket client dependency in the CI test matrix. Also apply ruff
formatting to the files the formatter check was rejecting so the 3.12 lint
job passes.
2026-04-20 22:12:01 +07:00
Adryan Eka Vandra
6bc44b3e00
chore(deps): refresh uv.lock to schema revision 3
Upgrade of the local uv CLI rewrote the lock file with `revision = 3`
and renamed the metadata key `upload_time` -> `upload-time`. No actual
dependency version changes.
2026-04-20 22:09:57 +07:00
JerrettDavis
a1beb08d53 feat: add reproducible devcontainers
Add a default devcontainer and a compose-backed memory-stack profile, validate them in CI, and document the contributor workflow.

Also lock the memory-stack dependencies, pin related container tooling, and sync the latest healthcheck shutdown fix for stubbed memory handlers.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-10 12:58:35 -05:00
JerrettDavis
7d02829f02 Harden Anthropic prefix cache stability across proxy and batch paths 2026-04-04 13:45:37 -05:00
chopratejas
40369762dd Add Cloud mode to ASGI middleware and LiteLLM callback
Both CompressionMiddleware and HeadroomCallback now support a cloud mode
(api_key="hdr_xxx") that calls Headroom Cloud API for managed compression
with org-scoped CCR, TOIN learning, and analytics. Falls back to
HEADROOM_API_KEY env var. Local mode (default) is unchanged.

Also adds x-headroom-tokens-before/after response headers and updates
uv.lock with mcp extra and version bump to 0.3.3.
2026-02-27 20:10:07 -08:00