transport: move the daemon endpoint to /tmp/felis.<uid> #283
No reviewers
Labels
No labels
priority/P0
priority/P1
priority/P2
release/v0.1.0
status/blocked
status/planned
type/bug
type/design
type/test-gap
type/tracker
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
natsukium/felis!283
Loading…
Reference in a new issue
No description provided.
Delete branch "issue-282"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes #282
What changed
/tmp/felis.<uid>/daemon.sockon Linux and macOS.XDG_RUNTIME_DIR,TMPDIRand/run/user/<uid>no longer take part;--socketandFELIS_SOCKETstillwin.
/tmphas boot lifetime, which a login's runtime directory does not, so a relay under Tailscale SSH, adesktop login and an SSH login all reach one daemon, and a forked daemon stays reachable after the last
logout on a non-lingering systemd host. tmux derives
/tmp/tmux-<uid>the same way.flockon the socketdirectory, opened
O_DIRECTORY | O_NOFOLLOW | O_CLOEXECand judged from that descriptor (owned by thisuid, mode exactly
0700). The lock leaves no file behind and is released whenbindreturns, so a servingdaemon holds nothing and a later starter never waits on it. One
lstatafter the bind confirms the parent isstill the directory that was judged. The bind runs under
umask 0177, so the socket is0600with no chmodwindow.
lstats first and classifies: a directory or a symlink at the endpoint fails the startuntouched, a non-socket inode is removed, and a socket is connected to (a listener of this uid means
AddrInUse, one of another uid fails the start, and only the absence errors license the unlink).create_dirratherthan
create_dir_all, so a--socketwhose grandparent is missing is reported instead of materialized, and aparent that cannot be opened (the foreign-owned
0700squat) is aParenterror carrying its owner, its mode,and the recovery rather than a bare
Permission denied.Listener::dropnever unlinks (REQ-009d), so a dying daemon cannot remove a newer daemon's socket. Thecost is one stale socket file that the next start replaces, and
felis doctorsays so rather than invitingan
rm; anything else at the path is named, because the next start refuses it instead.listener ends before the preface and the relay never sends its carrier block.
felis doctorloses the old-location candidate probes: with no environment in the derivation there is nosibling location to probe. The stamped-target row stays and now reports the default's state either way: a daemon
answering it warns, a cold default is an
okrow saying so.reference; session lifecycle; non-goals; the two how-tos; workspace; security audits),
CHANGELOG.md, theshipped skill and three agent skills, and the smoke recipes in
justfileand both Forgejo workflows (asocket directly under a shared
/tmpis refused now that the parent is judged).What the plan leaves out on purpose
No watch or drain of the socket directory, no per-instance agent link names, no doctor candidates for old
build locations, no
confstrpath on macOS, no<socket>.lockfile, no served-socket proxy, no retry looparound the bind (the single post-bind parent check is built), no descriptor-relative agent-link writes, no
maintenance task, no
.agentlength validation.agent.rsis unchanged. Decision 4 builds nothing: thesystemd hand-off keeps its behavior, and the docs state the linger condition that ends such a daemon.
One deviation to flag: the plan asked the smoke recipes to create their per-run
0700directory withmktemp -d. The workflow's run step and its stop step need the same path andmktemp -dcannot hand onebetween them, so the directory is named
felis-smoke-${{ github.run_id }}(per-run isolation as before) andthe daemon creates it
0700.Verification
just check: pass, 3571 tests run: 3571 passed, 16 skipped.just check-windows: pass.The endpoint was resolved from XDG_RUNTIME_DIR, then /run/user/<uid>, then ${TMPDIR:-/tmp}/felis.<uid>. Every one of those is login-scoped: a relay under Tailscale SSH carries no XDG_RUNTIME_DIR and lands on a second daemon with its own session roster, and on a non-lingering systemd host logging out of the last session takes /run/user/<uid> down under a forked daemon that is still alive and now unreachable. /tmp/felis.<uid> has boot lifetime and needs no lookup and no variable, which is why tmux derives /tmp/tmux-<uid> the same way. macOS keeps a per-boot directory of its own, but reaching it needs confstr through FFI and it is per-session under some sandboxes, so both platforms use the same /tmp path. A user who wants another location still has FELIS_SOCKET and --socket. Assisted-by: Claude Code0ae4ec068f782021c267782021c267634b16de66