Repository navigation
Read the Local Instruction File Only When It Is a Regular File - #2428
Conversation
A FIFO or device at the local instruction path passed the lstat check and then blocked the read, hanging both the install and --report. Only a regular file is read now, anything else stops the run with nothing changed, and the stamp reader skips a stamp that is not a regular file for the same reason. Refs #2423 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An is_file() check before the read left a window to swap the path and gave a different message on Python 3.14, where is_file() swallows every OSError. read_regular_file() opens once with O_NONBLOCK and checks the descriptor with fstat, so a FIFO or device returns None without blocking on every version. The stamp guard is dropped, since the stamp is read and written unguarded elsewhere, and the FIFO cases run bounded so a regression fails rather than hangs. Refs #2423 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
os.fdopen raised on a directory without closing the descriptor it was handed, so read_regular_file leaked one per directory read. It now judges and reads the raw descriptor and closes it in a finally, which also lets a directory reach the regular-file check. A file deleted between the lstat and the open is now said to no longer exist, keeping "a link that leads to nothing" for an actual link. Refs #2423 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configuration
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## develop #2428 +/- ##
========================================
Coverage 58.47% 58.47%
========================================
Files 16 16
Lines 8062 8062
========================================
Hits 4714 4714
Misses 3348 3348
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Dangling links through non-directory path components need consistent classification before approval.
Review effort: Lite
Findings: 1
Open (1)
What changed in this PR
Updates the Claude host-safety installer to safely read only regular local instruction files without blocking on FIFOs or devices.
Changes:
- Adds descriptor-based, nonblocking reads with guaranteed cleanup.
- Adds FIFO, report, and descriptor-leak regression coverage.
- Documents regular-file validation and refusal behavior.
| File | Reviewed changes |
|---|---|
host-setup/agent-safety/claude/install.py |
Implements safe regular-file reads; requires consistent dangling-link handling and comment cleanup. |
host-setup/agent-safety/claude/test_install.py |
Adds bounded FIFO and descriptor-cleanup tests; updates an outdated test docstring. |
host-setup/agent-safety/claude/README.md |
Documents regular-file validation and refusal behavior. |
💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Refs #2423 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
A recorded local strict-review pass covers head |
## Summary Promotes `develop` to `main` with four pull requests, each already reviewed and merged into `develop`: - [#2424](#2424) Render the Whole Global CLAUDE.md and Back Up a Hand Edit. - The host-safety installer now owns all of `~/.claude/CLAUDE.md`. It renders a header, the two existing blocks, and a shared host-local file, `agent-fleet/local.md`. - It replaces an earlier render silently. A file edited by hand, or one written before this change, is copied to a timestamped `.bak` first. - `merge-and-release` step 7 now also runs this kit's `--report`, so a release flags a stale host. - [#2427](#2427) Render CLAUDE.md First and Let the Real Write Be the Check, the fix for this PR's Copilot finding. - [#2428](#2428) Read the Local Instruction File Only When It Is a Regular File, the fix for this PR's previously-missed Copilot finding. - [#2429](#2429) Refuse a Local Instruction Path Whose Parent Is a File, the fix for this PR's third-round Copilot finding. On a host's next install, the existing `CLAUDE.md` is backed up and replaced. Anything host-specific moves into the local file. Closes #2423 🤖 Generated with [Claude Code](https://claude.com/claude-code)

Summary
This fixes the finding Copilot flagged on promotion PR #2425 as "previously missed".
read_local_instructionschecked the local instruction file withlstatand then read it directly. A FIFO or a character device at that path blocked the read forever, which hung both the install and--report.A new
read_regular_file()opens the path once and judges the open descriptor. It opens withO_RDONLY|O_NONBLOCKand checks the descriptor withfstatandS_ISREG, so a FIFO or a device returnsNonewithout blocking. The check and the read are one operation, so nothing can swap the path between them.The descriptor is closed in a
finallyon every path. An intermediate version leaked one per directory read, becausefdopenraised without closing what it was handed.Refusal messages:
The same message appears on Python 3.11, 3.13 and 3.14. An
is_file()check would have differed on 3.14, which swallows everyOSError.The FIFO cases run with a bound, so a regression fails the test rather than hanging the suite. The report case installs first and then asserts the refusal.
The same FIFO gap exists, from before this change, at
settings.jsonand the stamp. It's recorded on #2426, withread_regular_file()as the shape to reuse.Refs #2423
Verification
python3 -m unittest test_install: 123 tests OK on 3.13 and on 3.14. The edge cases also pass on 3.11.🤖 Generated with Claude Code