Conversation
… with user suffix
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
📝 WalkthroughWalkthroughDaemon IPC files now use per-user paths, daemon cleanup is lock-guarded and unwind-safe, signal handling enables clean shutdown, and ChangesDaemon files and lifecycle
Estimated code review effort: 4 (Complex) | ~40 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
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 |
PR Summary by QodoClean up daemon exits and isolate runtime files per user
AI Description
Diagram
High-Level Assessment
Files changed (2)
|
Code Review by Qodo
Context used✅ Compliance rules (platform):
11 rules 1.
|
- Serialize daemon startup and cleanup with a lock file so an exiting daemon can't delete files a replacement just rebound (TOCTOU race) - Sweep pre-uid-suffix legacy files in kill-daemon so daemons started by older binaries can still be stopped after an upgrade - Reword shutdown_signal doc comment to capture rationale - Update README/AGENTS.md to the uid-suffixed daemon paths Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
@coderabbitai full review |
✅ Action performedFull review finished. |
|
/agentic_review |
|
Code review by qodo was updated up to the latest commit 421eca5 |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@README.md`:
- Around line 218-221: Update README.md lines 218-221 to separate Unix and
Windows daemon transports and cleanup guarantees: document the UID-suffixed Unix
socket and signal handling, the Windows loopback TCP listener with the
unsuffixed address file, and best-effort Ctrl-C cleanup. Qualify the Unix-socket
architecture diagram at README.md line 44 or add the Windows transport. Qualify
the UID-suffixed socket and signal-cleanup statements in AGENTS.md lines 65-68
as Unix-specific.
In `@src/daemon.rs`:
- Around line 32-45: Update lock_daemon_files to return
anyhow::Result<std::fs::File> and propagate descriptive errors from opening and
locking the daemon lifecycle lock instead of converting failures to None. Make
daemon startup handle this result and fail with the reported context, while
preserving best-effort unlocked behavior only in the cleanup path that handles
lock contention.
In `@src/lib.rs`:
- Around line 999-1017: Update the legacy PID handling in the kill-daemon flow
around legacy_pid_path so it does not call libc::kill based solely on the parsed
PID. Verify that the PID belongs to this daemon using an available
daemon-specific identity check before sending SIGTERM; when identity cannot be
confirmed, avoid signaling and only remove files when staleness is safely
established, otherwise leave them for manual intervention.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 1e8d53b9-443c-4b8f-8692-c7a1d3cba527
📒 Files selected for processing (5)
AGENTS.mdREADME.mdsrc/daemon.rssrc/lib.rssrc/protocol.rs
- Surface lock-file failures: daemon startup now fails explicitly when the daemon-file lock cannot be created or acquired, and cleanup distinguishes WouldBlock contention (silent skip by design) from I/O errors (reported to stderr) - Extract PID-file parsing into a pure parse_pid_file_contents helper - Probe the legacy socket before signaling: kill-daemon only SIGTERMs a legacy PID after a daemon answers on the legacy socket, so a recycled PID can never hit an unrelated process; dead sockets get their stale files removed without any signal Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Document the Windows loopback TCP listener and unsuffixed %TEMP% addr file alongside the uid-suffixed Unix socket, and mark signal cleanup as Unix-specific (Windows Ctrl-C is best-effort — no console when backgrounded) in README and AGENTS.md. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
/agentic_review |
|
@coderabbitai full review |
✅ Action performedFull review finished. |
|
Code review by qodo was updated up to the latest commit 42f60b9 |
- probe_legacy_daemon returns anyhow::Result<bool>: connect-refused and missing socket stay Ok(false), unexpected connect/write/read failures carry operation-specific context, and kill-daemon handles Err by warning and leaving files in place (a probe timeout no longer counts as "stale" and deletes files under a live listener) - probe timeout now spans the whole connect/write/read sequence so a hostile listener on the predictable socket name can't stall any step - lock file opens with O_NOFOLLOW + mode 0600 and validates regular file + current-uid ownership before locking; startup lock wait is bounded (5s) instead of blocking indefinitely on a squatted lock - SKILL.md: explain why DevToolsActivePort existence is the readiness signal instead of restating the polling loop Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
/agentic_review |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (3)
README.md (1)
217-226: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winLock file not mentioned in daemon file inventory.
This cohort introduces a persistent
lock_path()file (never removed, per its doc comment inprotocol.rs) used to serialize startup/cleanup, but "Daemon details" and the manual-cleanup note ("delete the socket + PID file") don't mention it. A user manually cleaning up daemon artifacts wouldn't know it exists.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@README.md` around lines 217 - 226, Update the “Daemon details” file inventory and manual cleanup guidance to include the persistent lock file created by lock_path(). State its platform-specific location if applicable, note that it is intentionally not removed automatically, and include it in the artifacts users should delete during manual cleanup.src/lib.rs (2)
488-500: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd unit tests for
parse_pid_file_contents.This is a pure conversion function (trim/parse/validate) with no accompanying tests — worth covering edge cases (
"0", negative-after-cast values, overflow beyondi32, non-numeric, whitespace-only).As per coding guidelines,
src/**/*.rs: "Extract pure conversion and formatting logic into testable functions" and "Place tests in#[cfg(test)] mod testswithin the same source file."✅ Example test module
#[cfg(test)] mod tests { use super::*; #[test] fn rejects_zero() { assert_eq!(parse_pid_file_contents("0"), None); } #[test] fn rejects_overflow() { assert_eq!(parse_pid_file_contents("4294967295"), None); } #[test] fn accepts_valid_pid() { assert_eq!(parse_pid_file_contents(" 1234 \n"), Some(1234)); } #[test] fn rejects_garbage() { assert_eq!(parse_pid_file_contents("abc"), None); } }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/lib.rs` around lines 488 - 500, Add a #[cfg(test)] mod tests in src/lib.rs using super::* to cover parse_pid_file_contents: reject zero, negative-after-cast inputs, values exceeding i32, non-numeric and whitespace-only strings, and accept trimmed valid PIDs. Keep the tests focused on this pure conversion function.Source: Coding guidelines
957-991: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winConsider reusing
parse_pid_file_contentshere instead of duplicating pid-validation logic.This block re-implements the same "reject 0 / must fit
i32" checks thatparse_pid_file_contents(lines 494-500) now centralizes for the legacy path. Consolidating avoids two independently-maintained copies of the same safety check, though you'd want to keep this path's more descriptive per-failure error messages.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/lib.rs` around lines 957 - 991, The PID-reading flow around the Unix signal handling should reuse parse_pid_file_contents for the shared PID 0 and i32-range validation instead of duplicating those checks. Preserve this path’s descriptive error context by mapping or augmenting parser errors with pid_path details, then continue using the validated PID for libc::kill.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/daemon.rs`:
- Line 1: Declare the minimum supported Rust version/toolchain for the file_lock
crate at the project configuration level, setting it to Rust 1.89 or newer to
match the std::fs::File::lock/try_lock and std::fs::TryLockError APIs used by
the daemon lock path. Update the appropriate Cargo.toml or toolchain
configuration rather than changing the daemon implementation.
In `@src/lib.rs`:
- Around line 1041-1057: Update the legacy daemon branch around
probe_legacy_daemon and libc::kill so failures other than ESRCH are surfaced,
especially EPERM, with a diagnostic indicating the daemon may still be running
and could not be signaled. Preserve cleanup for successful termination or ESRCH,
and keep the existing stopped-daemon message unchanged.
---
Nitpick comments:
In `@README.md`:
- Around line 217-226: Update the “Daemon details” file inventory and manual
cleanup guidance to include the persistent lock file created by lock_path().
State its platform-specific location if applicable, note that it is
intentionally not removed automatically, and include it in the artifacts users
should delete during manual cleanup.
In `@src/lib.rs`:
- Around line 488-500: Add a #[cfg(test)] mod tests in src/lib.rs using super::*
to cover parse_pid_file_contents: reject zero, negative-after-cast inputs,
values exceeding i32, non-numeric and whitespace-only strings, and accept
trimmed valid PIDs. Keep the tests focused on this pure conversion function.
- Around line 957-991: The PID-reading flow around the Unix signal handling
should reuse parse_pid_file_contents for the shared PID 0 and i32-range
validation instead of duplicating those checks. Preserve this path’s descriptive
error context by mapping or augmenting parser errors with pid_path details, then
continue using the validated PID for libc::kill.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 956a0e72-6461-455d-868f-90ab242230b6
📒 Files selected for processing (6)
AGENTS.mdREADME.mdskill/chrome-devtools/SKILL.mdsrc/daemon.rssrc/lib.rssrc/protocol.rs
|
Code review by qodo was updated up to the latest commit 517354b |
- Declare rust-version 1.89 (std File::lock/try_lock/TryLockError floor) - Legacy kill-daemon branch reports non-ESRCH signal failures (e.g. EPERM) instead of silently leaving a live daemon unmentioned - Main kill-daemon path reuses parse_pid_file_contents instead of duplicating the pid-0 and pid_t-overflow guards; add unit tests for the parser - Document the persistent daemon lock file in README Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- open_lock_file returns anyhow::Result with per-operation context (open vs metadata vs ownership validation) so callers no longer mislabel metadata failures as open failures - Legacy kill-daemon sweep only removes files when the named process is verifiably gone: old binaries write their PID before binding and don't take the startup lock, so an unanswered socket alone could be a daemon mid-startup Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- lock_daemon_files polls with tokio::time::sleep instead of thread::sleep so a contended lock never blocks a runtime worker - Add SAFETY comments to all unsafe getuid()/kill() call sites - Document cleanup() stderr visibility (foreground debugging only), the accept-loop macro's contract (re-evaluated accept future, pinned shutdown future, why it isn't a generic fn), the legacy probe's reply-to-malformed-request assumption and its safe failure mode, and parse_pid_file_contents' kill-daemon-only scope Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
/agentic_review |
|
Code review by qodo was updated up to the latest commit 79270e2 |
|
/agentic_review |
|
Code review by qodo was updated up to the latest commit 5e8ed26 |
Review fixes for the daemon-cleanup changes: - kill-daemon no longer trusts pid files by path alone: reads go through read_pid_file_checked (O_NOFOLLOW|O_NONBLOCK, regular-file + owner-uid check, 64-byte cap), closing a confused-deputy SIGTERM via a planted pid file at the predictable (especially legacy, unsuffixed) names in shared /tmp. - probe_legacy_daemon checks peer credentials: a listener on the legacy socket running as another uid is treated as a squatter (Err -> files left alone), not as our daemon. - open_lock_file gains O_NONBLOCK so a planted FIFO can't wedge open(). - LOCK_WAIT_TIMEOUT 5s -> 2s so a lock-delayed daemon still binds inside the client's 5s wait_for_daemon budget instead of losing the race. - Signal streams register eagerly (before lock/bind), closing the startup window where SIGTERM skipped CleanupGuard; a stream that registered while its sibling failed is now still drained instead of swallowing that signal. - Tests for the invariants the design rests on: lock-path symlink/FIFO rejection, cleanup foreign-pid no-op, lock-never-removed, and contention back-off (via path-parameterized open_lock_file_at / cleanup_at). - SKILL.md Pattern 16: cleanup runs via an EXIT trap on every failure path; readiness wait bounded at 30s with a Chrome liveness check. - Minor: drop no-op _lock rebind, user_suffix returns Cow, rustfmt. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
/agentic_review |
|
Code review by qodo was updated up to the latest commit 420f17b |
- read_pid_file_checked returns anyhow::Result with path-aware context on open/metadata/read; callers recover the absence case by downcasting the chain via the new pid_file_missing() helper instead of matching io kinds. - Reject PID files larger than 64 bytes instead of silently truncating: the reader takes one byte past the cap so an oversized file can be detected, since a truncated prefix can still parse as a PID that reaches kill(). - Derive the daemon startup lock wait from the client's own budget (min(DAEMON_WAIT_TIMEOUT_SECS / 2, 2s)) so it stays strictly shorter than every accepted value, not just the 5s default. A daemon that spent the whole budget on the lock would bind exactly as wait_for_daemon gave up. - SKILL.md headless recipe: wait for CHROME_PID to exit before removing the profile, bounded at 5s with SIGKILL escalation, so cleanup can neither race Chrome's async teardown nor hang on a Chrome that ignores SIGTERM. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
/agentic_review |
|
Code review by qodo was updated up to the latest commit 48dba36 |
The 1.89 floor (File::{lock, try_lock}) only lived in a Cargo.toml comment,
so a `cargo install` on an older toolchain surprised users; there is no
changelog, so the README's Installation section is where it belongs.
Also move the "legacy daemons might stop answering malformed requests"
caveat from the fn doc down to the probe payload itself, where the
assumption is actually encoded.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
std::fs::write opens O_CREAT|O_TRUNC and follows symlinks, so it was the one hostile-path hole the read side didn't cover: on Linux's shared /tmp another user could pre-create chrome-devtools-daemon-<victim-uid>.pid as a symlink to any file the victim can write, and the first CLI invocation would truncate it and write a PID in. The startup lock is no defense — the squatter never takes it and it guards a different path. write_pid_file_checked mirrors open_lock_file_at: O_NOFOLLOW, O_NONBLOCK, mode 0o600, regular-file/owner-uid validation against the open fd, and the truncation deferred until after those checks pass. Tested for the symlink attack (target contents untouched), stale-content replacement, and mode. Also from review: - cleanup() reads the PID file through read_pid_file_checked instead of a bare read_to_string, so the trust rule lives in one place. - `biased;` in the accept loop's select! so a ready shutdown signal always beats a ready accept rather than being chosen at random. - Document that SIGQUIT/SIGHUP/SIGKILL skip cleanup by design, that kill-daemon returns on signal delivery rather than exit, and how to stop a daemon on Windows. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
/agentic_review |
|
Code review by qodo was updated up to the latest commit 7f8e85a |
The kernel stamps a new file with the creating process's effective uid, so the ownership checks had to compare against geteuid(): under a setuid binary or a credential-transitioning launcher (uid != euid), the daemon would create its PID/lock file and then immediately reject it as another user's, failing startup and skipping cleanup. The per-user filename suffix moves to geteuid() for the same reason — the identity the paths are keyed to must be the identity the checks enforce, or the files land at a path derived from one uid and get judged against another. Where uid == euid (all ordinary runs) the paths are byte-identical, so this is not a compatibility break. Also covers the legacy-socket peer check, where both sides were already effective uids: peer_cred reports the peer's euid. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
/agentic_review |
|
Code review by qodo was updated up to the latest commit 93adb70 |
Summary by CodeRabbit
New Features
$TMPDIRlocations to avoid cross-user conflicts.kill-daemonnow detects and stops older “legacy” daemons when present.Bug Fixes
Documentation