Two additional codex findings on 6d412c9:
1. _ipc.identify() accepted any int as pid, including 0 and negatives.
On POSIX, os.kill(0, sig) signals every process in the calling
process group, and os.kill(-1, sig) signals every process the
caller can. A hostile or buggy daemon replying {pid: 0} or
{pid: -1} would have turned restart_daemon() into a process-group
kill. Restrict to pid > 0.
2. _ipc.ping() still did resp.get('pong') without a type check, so a
list/scalar/null reply would raise AttributeError. The previous
commit added that guard to identify() but left ping() bare. With
the new daemon_alive fallback in restart_daemon() that now calls
ping(), an unhandled raise here would abort restart before
cleanup ran. Mirrored the identify() guards: isinstance(resp, dict)
plus AttributeError in the except.
Tests in tests/unit/test_ipc.py now also cover:
- identify() rejects pid=0, pid=-1, pid=-42, pid=-99999
- ping() returns False for non-dict payloads (list/str/int/None)
- ping() requires pong is exactly True (rejects truthy non-True values)
Full suite: 71 passed.
Two related cubic/codex findings on _ipc.identify():
1. isinstance(pid, int) accepts bool (since bool subclasses int in
Python), so a hostile or buggy daemon replying {pid: True} would
yield PID 1 and os.kill(1, SIGTERM) would target init on POSIX.
Switched to type(pid) is int — strict same-type check, no subclass
surprises.
2. request() returns whatever JSON the daemon sent, which can be a
list, scalar, or None for a stale/hostile endpoint. resp.get(...)
would then raise AttributeError, propagating out of identify() and
crashing restart_daemon() before its cleanup runs. Added an
isinstance(resp, dict) guard and AttributeError to the except.
Tests in new tests/unit/test_ipc.py cover both rejections plus the
happy path, the missing-pid path (pre-upgrade daemon), pong=False,
and several non-dict shapes (list, str, int, None). Full suite: 67
passed.