Skip to content

Release: the daemon removes its activity socket and directory on shutdown - #453

Merged
node9ai merged 3 commits into
mainfrom
dev
Nov 4, 2026
Merged

node9ai merged 3 commits into
mainfrom
dev

Conversation

@node9ai

@node9ai node9ai commented Nov 4, 2026

Copy link
Copy Markdown
Member
  • node9 daemon stop, systemd and launchd stop the daemon with SIGTERM, which used to end it without the 'exit' event: the activity socket stayed, and nothing ever removed its per-HOME directory under XDG_RUNTIME_DIR. A harness that starts many daemons with throwaway HOMEs left one directory per HOME in /run/user/, a tmpfs. SIGTERM (exit 0), SIGINT (130) and SIGHUP (129) now run the same clean-up as a normal exit.
  • The clean-up unlinks only the socket file this daemon bound (dev/ino recorded at bind), then removes the directory only when it is this HOME's directory under XDG_RUNTIME_DIR (never ~/.node9/run or another HOME's), a private directory of this user (not a link), and empty. SIGKILL still leaves the directory; the next start reuses it.
  • Code review fix: two daemons with one HOME share one socket path. The socket now starts only once the daemon owns the HTTP port, so a second start that yields, or a newer build taking over, no longer replaces or removes the live daemon's socket (before: a 2 s gap until a rebind, and five rebinds in a minute trip the circuit breaker).
  • Tests: isolated daemons (own HOME, own XDG_RUNTIME_DIR, own port) for SIGTERM, SIGINT, SIGHUP, daemon stop, a non-empty directory, a link, SIGKILL then restart, a yielding second start and a takeover. The new tests fail without the fix.

CI green on dev 638d65a.

🤖 Generated with Claude Code

node9ai and others added 3 commits November 4, 2026 08:04
The daemon had no SIGTERM or SIGINT handler, so `node9 daemon stop`, which
sends SIGTERM, ended it without the 'exit' event: the activity socket stayed,
and nothing ever removed its per-HOME directory under XDG_RUNTIME_DIR. A
harness that starts many daemons with throwaway HOMEs left one directory per
HOME in /run/user/<uid>, a tmpfs.

SIGTERM now exits 0 and SIGINT 130 through process.exit(), so the existing
'exit' clean-up runs once. That clean-up closes the activity server, unlinks
the socket only when it is ours, then removes the directory only when it is
this HOME's directory under XDG_RUNTIME_DIR (never ~/.node9/run or another
HOME's), a real directory of this user, and empty. SIGKILL still leaves the
directory; the next start reuses it as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review of the shutdown clean-up (ae8b18c) found that two daemons with one
HOME, which share one socket path, removed each other's socket:

- The activity socket started before the HTTP port was owned, so a second
  start that then yields, or a newer build taking over, first replaced the
  live daemon's socket.
- On the way out, Node's server.close() unlinks whatever file is at the
  path, and the uid-only ownership check passes for every daemon of this
  user. The exiting daemon removed its successor's socket and directory; the
  successor was without one until its 2 s probe rebound it, and five such
  rebinds in a minute trip the circuit breaker.

The socket now starts in the listen callback, once this process owns the
port. Shutdown no longer closes the server (the process ends anyway) and
unlinks the socket only when its dev/ino match the file this daemon bound.
SIGHUP (a foreground daemon's terminal closed) now exits 129 through the
same clean-up. removeOwnSocketDir reuses isPrivateDir.

Tests: a yielding second start and a takeover keep the survivor's socket
(no rebind, same inode); SIGHUP cleans up; the stop test allows a slow CLI
start on a loaded runner.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ned (fw#320)

At the observe level the gate reaches its block or review and the level
records it without stopping the call. The summary counted such an attack
as undetermined whenever an input was not reproduced (the package
registry), although its outcome is known: it goes through and is logged.
On a workspace in observe this moved 50 of 135 headline attacks out of
the count. Undetermined now means an allowed attack whose unreproduced
input could have stopped it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Nov 4, 2026

Copy link
Copy Markdown
Contributor

🛡️ node9 agent-security · ✅

This PR introduces no agent-security findings.

0 finding(s) · · technical details

@node9ai
node9ai merged commit 296851b into main Nov 4, 2026
13 checks passed
@node9ai

node9ai commented Nov 4, 2026

Copy link
Copy Markdown
Member Author

🎉 This PR is included in version 2.50.1 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant