fix(provision): never block startup on a missing fduty CLI; stage it on binary-only installs#71
Merged
Merged
Conversation
…on binary-only installs Two coupled defects made a runner refuse to start when the `fduty` CLI was absent — most visibly on macOS, where it failed immediately with "fduty CLI not ready" after install.sh reported "Already at vX, nothing to do". 1. Startup gate was fatal. `ensureFdutyCLI` returned an error that aborted run/serve when fduty couldn't be provisioned or verified. A runner can still do non-fduty work, and a missing CLI is far easier to fix on a running, loudly-logging runner than on one that won't boot. It is now best-effort: it still auto-stages and self-checks fduty, but on failure it logs an actionable manual-install hint and the runner starts anyway. fduty calls 127 until the operator resolves it — surfaced, not silently fatal. 2. install.sh never staged the bundled fduty on binary-only / darwin installs. `install_bundled_fduty` sat after the early `return` taken on the darwin/--no-service path, so the fduty shipped inside the release archive was extracted but never placed. Renamed to `stage_bundled_fduty(dir)` and now called on both paths: service installs stage into $BIN_DIR (the env-pinned runtime tools dir), binary-only/darwin into $INSTALL_DIR (on the user's PATH, and the dir darwin's bundledFdutyNextToExe() probes since os.Executable() there returns the /usr/local/bin symlink, not its target). The "already up to date" short-circuit now also requires `fduty_present` (mode-aware) so a re-run self-heals a missing fduty instead of declaring success while the CLI is absent. Verified: runner boots through to the WS-connect stage with fduty fully absent (no abort); install.sh staging + short-circuit logic unit-tested; go build/vet/test, gofumpt, shellcheck all green.
ysyneu
added a commit
that referenced
this pull request
Jun 15, 2026
release(v0.0.23): fduty startup gate non-fatal + install.sh binary-only staging (#71)
This was referenced Jun 15, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
A runner refused to start when the
fdutyCLI was absent — most visibly on macOS, whereflashduty-runner servedied immediately withfduty CLI not readyright afterinstall.shreported "Already at vX, nothing to do."Two coupled defects:
ensureFdutyCLI() errorabortedrun/servewhen fduty couldn't be provisioned/verified.install_bundled_fdutysat after the earlyreturnon the darwin/--no-servicepath, so the fduty bundled inside the release archive was extracted but never placed. Re-running install.sh didn't help either: the "already up to date" short-circuit returned before staging.Net on macOS: no fduty anywhere the runtime looks → the (then-fatal) gate bricked startup.
Fix
Gate is now non-fatal (
cmd/provision.go,serve.go,main.go).ensureFdutyCLI()still best-effort auto-stages fduty and self-checks it on the bash PATH, but on failure it logs an actionable manual-install hint and the runner starts anyway. A runner can still do non-fduty work, and a missing CLI is far easier to fix on a running, loudly-logging runner than on one that won't boot.fdutycalls 127 until the operator resolves it — surfaced, not silently fatal.install.sh staging fixed.
install_bundled_fduty→stage_bundled_fduty(dir), now called on both paths:$BIN_DIR(env-pinned runtime tools dir)$INSTALL_DIR(on the user's PATH, and the dir darwin'sbundledFdutyNextToExe()probes —os.Executable()there returns the/usr/local/binsymlink, not its target; verified empirically)The "already up to date" short-circuit now also requires
fduty_present(mode-aware) so a re-run self-heals a missing fduty instead of declaring success while the CLI is absent.Verification
runwith fduty fully scrubbed from PATH + an empty bin dir → it logs the install hint and proceeds throughworkspace initialized→health server listening→connecting to Flashduty(only exits on the bogus WS URL, not on fduty). Before this change it aborted right after "starting".TestEnsureFdutyCLI_NeverFatalWhenUnprovisionable(deterministic missing-fduty branch via scrubbed PATH); extracted-function tests forstage_bundled_fduty+fduty_present(stage-to-INSTALL_DIR, stage-to-BIN_DIR, present/absent, no-fduty-member no-op).go build ./...,go vet ./...,go test ./...,gofumpt -l,shellcheck -s sh install.sh— all green.Notes
provisionFduty/verifyFdutyOnPathkeep their error-returning contracts (still unit-tested); only theensureFdutyCLIintegration point swallows the error into a log.