Repository navigation
Description
fleet(secrets-broker): SECRETS_BROKER_TTL_S=0 makes the vault-refresh loop spin — ~110 full bws refreshes per second, no startup validation
Evidence
pkgs/fleet/crates/fleet-queue/src/secrets_broker.rs:204-207 parses the TTL with no validation:
let ttl_s: u64 = std::env::var("SECRETS_BROKER_TTL_S")
.ok()
.and_then(|v| v.parse().ok())
.unwrap_or(900);and the background refresh loop at secrets_broker.rs:219-228 sleeps exactly that long between full vault refreshes:
loop {
match refresh(&state) { ... }
std::thread::sleep(Duration::from_secs(ttl_s));
}Each refresh() is a full vault fetch: one bws secret list plus one bws secret get per secret (8-way pool, do_refresh at secrets_broker.rs:111-185).
Verified this run on the laptop with the real standalone secrets-broker binary and a stub bws on PATH that counts invocations (probe ~/git/fleet/probe-secrets-ttl-b, stub returns one secret):
SECRETS_BROKER_TTL_S=0: 882bwscalls in 4 seconds (~441 list+get refresh cycles, ≈110 full vault refreshes/sec, sustained — the sleep is zero-length).- Controls in a sibling probe (
~/git/fleet/probe-secrets-ttl):TTL_S=900andTTL_S=abceach made exactly 1 refresh (2 calls) in 3s.
Two defects:
- Zero (and by extension any pathologically small) TTL is accepted. A single typo'd env value (
SECRETS_BROKER_TTL_S=0in a unit file / Nix module) turns a resident daemon whose whole purpose is to avoid hammering Bitwarden (module doc,secrets_broker.rs:3-7: it replaces per-callbwsfetches that cost 10–40s each) into a process that hammersbwscontinuously, burning CPU and vault API quota for as long as it runs. - An unparseable TTL silently becomes 900.
TTL_S=abc(or a negative value, which fails theu64parse) loads with no warning, so an operator who set e.g.TTL_S=60sgets 900s staleness and no signal why.
Why it matters
The secrets broker sits on the fleet's credential path (repo-queue and every fleet secrets get consumer). A busy-looping broker degrades the laptop it shares with all other fleet work and can trip Bitwarden rate limits — taking down secret access fleet-wide — from one bad env value that startup never questioned. Sibling numeric env/config values in this codebase are startup-validated (e.g. atlas-search validate_limits, code#5630); this one is not.
Acceptance criteria
-
SECRETS_BROKER_TTL_S=0(and any value below a stated sane minimum) is refused at startup with a clear error naming the variable and value, OR clamped to the minimum with a loud log line — pick one behaviour and pin it with a test. - An unparseable
SECRETS_BROKER_TTL_Sproduces a visible warning (log or stderr) naming the value and the 900s default being used, instead of silently defaulting. - A test pins the TTL parsing/validation (extract a pure helper if needed): unset → 900, valid value → that value, zero/below-minimum → the chosen refusal/clamp, garbage → default + warning path.
- Re-probe with the stub-
bwsharness: at the minimum accepted TTL, refresh cycles in a fixed window match the configured rate (no spin).
Activity
developing-today commentedon Nov 5, 2026
CODE-1543
dezren39 commentedon Nov 5, 2026
🤖 Agent note · filed
dezren39 commentedon Nov 5, 2026
🤖 Agent note · handed off
opencode, so the task is handed off — the laptop opencode-claimant launches a bound session to drive it to its terminal state.dezren39 commentedon Nov 5, 2026
🤖 Agent note · filed (enqueue duplicate flag)
dezren39 commentedon Nov 5, 2026
🤖 Agent note · blocked
dezren39 commentedon Nov 5, 2026
🤖 Agent note · picked up