Repository navigation
Description
fleet-config: empty XDG env vars resolve to CWD-relative paths (a planted ./fleet/fleet.toml is loaded), and a relative FLEET_BROKER_SOCKET bypasses under-HOME resolution
Evidence (verified this run, laptop probe against the real crate @ main 3b3df1b)
Probe: ~/git/fleet/probe-fleetconfig-env on the laptop — a binary crate with a path dependency on pkgs/fleet/crates/fleet-config, driving the public API with controlled env vars (HOME=/tmp/fakehome123):
- A —
XDG_CONFIG_HOME="":Config::file_path()returns"fleet/fleet.toml"— a relative path. (pkgs/fleet/crates/fleet-config/src/lib.rs:file_path()mapsvar_os("XDG_CONFIG_HOME")straight intoPathBuf::fromwith no empty check; XDG base-directory spec says an empty value is invalid and must be treated as unset.) - B — with a planted
./fleet/fleet.tomlin the working directory ([domains] queue = false),Config::load()loads that file:domain_enabled("queue") == false. So from any directory containing a strayfleet/fleet.toml, fleet silently takes its config — including domain disables, broker socket, and token-file path — from the CWD instead of the user's~/.config/fleet/fleet.toml. - C — control,
XDG_CONFIG_HOMEunset:file_path()is/tmp/fakehome123/.config/fleet/fleet.tomland the planted file is ignored (queue_enabled=true). - E — same flaw in
state_dir():XDG_STATE_HOME=""returns relative"fleet", so the state/shims dirs also land in the CWD. - D —
broker_socket(): a relativeFLEET_BROKER_SOCKET(e.g..cache/laptop-agent/broker.sock, the default's own spelling) is returned as-is, CWD-relative, while the config-file value and the compiled default both go throughresolve_under_home— despite the field doc "relative paths resolve under $HOME". The same operator spelling therefore names different sockets depending on which source supplied it. Control: env unset →/tmp/fakehome123/.cache/laptop-agent/broker.sock.
Why it matters
fleet-config is the one place fleet configuration resolves, and its crate docs make a loud-error / no-silent-surprises contract (#5460 just enforced it for typos). Empty-string env vars are a routine artifact (systemd units, env -i wrappers, templated exports that expand to nothing), and here they quietly relocate the config file, the state dir, and — via a relative env socket — the broker endpoint to whatever directory the process happens to start in. The CWD-planted config case is the sharp edge: config content (domain disables = the incident lever, socket and token-file paths) becomes directory-dependent.
Acceptance criteria
- Empty
XDG_CONFIG_HOME/XDG_STATE_HOMEare treated as unset (fall back to~/.config/~/.local/state); emptyFLEET_CONFIGlikewise falls through to the XDG path instead of naming an empty path. - A relative
FLEET_BROKER_SOCKETenv value resolves under$HOME, exactly like the config-file and default values. - Regression tests pin: empty-XDG file/state paths are the HOME-based absolutes, and the env socket spelling
.cache/laptop-agent/broker.sockresolves to the same path as the default. cargo test -p fleet-configgreen (laptop or CI; no builds on the sandbox).
Activity
developing-today commentedon Nov 4, 2026
CODE-1332
dezren39 commentedon Nov 4, 2026
🤖 Agent note · filed
fix(fleet-config): treat empty env paths as unset; resolve env broker…
dezren39 commentedon Nov 4, 2026
🤖 Agent note · done