mirror of
https://github.com/headroomlabs-ai/headroom.git
synced 2026-08-27 14:17:10 -04:00
2 commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
9ce5af02b1
|
test(recover-codex): bind AF_UNIX socket via short relative path (#2396)
## Description `test_recovery_records_sockets_and_secures_both_backups` binds a Unix domain socket at its absolute path under pytest's `tmp_path`. On macOS the `AF_UNIX` `sun_path` limit (~104 bytes) is shorter than that path, so `bind()` raises `OSError: AF_UNIX path too long` and the test fails locally. It stays green on CI Linux only because `/tmp`-rooted temp paths there are short enough. Bind a short relative name from inside `source` instead; the socket is still created at `source/codex.sock` and the recovery scan behaves identically. Closes #2394 ## Type of Change - [x] Bug fix (non-breaking change that fixes an issue) ## Changes Made - `tests/test_cli/test_recover_codex.py`: in `test_recovery_records_sockets_and_secures_both_backups`, `monkeypatch.chdir` into `source` and `bind(socket_path.name)` (a short relative name) instead of `bind(str(socket_path))` (a long absolute path). Added the `monkeypatch` fixture to the signature and a one-line comment explaining the `sun_path` cap. ## Testing - [x] Unit tests pass (`pytest`) - [x] Linting passes (`ruff check .`) - [x] Type checking passes (`mypy`) - [x] Manual testing performed ### Test Output ```text # BEFORE (on this macOS box, at the branch base): $ uv run pytest -q \ "tests/test_cli/test_recover_codex.py::test_recovery_records_sockets_and_secures_both_backups" tests/test_cli/test_recover_codex.py:777: in test_recovery_records_sockets_and_secures_both_backups codex_socket.bind(str(socket_path)) E OSError: AF_UNIX path too long 1 failed in 0.70s # AFTER (whole file, no regressions): $ uv run pytest -q tests/test_cli/test_recover_codex.py 31 passed in 0.72s $ uv run ruff format --check tests/test_cli/test_recover_codex.py 1 file already formatted $ uv run ruff check tests/test_cli/test_recover_codex.py All checks passed! $ uv run mypy tests/test_cli/test_recover_codex.py Success: no issues found in 1 source file ``` <img width="1073" height="200" alt="image" src="https://github.com/user-attachments/assets/82155e76-3005-4c4f-93f4-4802ae5e7405" /> ## Real Behavior Proof - Environment: macOS 26.5 (darwin 25.5.0), Python 3.13.7, ruff 0.14.14, `tempfile.gettempdir()` = `/var/folders/.../T` (48 chars, before the `pytest-of-*/pytest-N/test_.../headroom-codex-home-broken/codex.sock` suffix, which pushes the absolute `sun_path` over the macOS ~104-byte cap). - Exact command / steps: run the focused test at the branch base (fails with `AF_UNIX path too long`), apply the one-line relative-bind change, re-run the whole file. - Observed result: before = 1 failed; after = 31 passed. `ruff`/`mypy` clean. - Not tested: Linux/Windows (the test is `skipif` on win32 / no `AF_UNIX`; on Linux it already passed pre-change because temp paths are short). No production code touched, so no proxy/runtime behavior was re-validated. ## 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 (N/A: test-only) - [x] My changes generate no new warnings - [x] I have added tests that prove my fix is effective or that my feature works (this IS the corrected test; it fails before and passes after) - [x] New and existing unit tests pass locally with my changes - [x] I did not edit `CHANGELOG.md` ## Additional Notes - Pure test-portability fix; no production behavior change. `test:` type keeps it out of the release-please changelog, which is correct for a test-only change. |
||
|
|
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 ` |