fix(services): re-invoke devbox by executable path, not hardcoded name (#1321) - #2936
Conversation
#1321) `devbox services start|stop|ls|restart|up` re-invoke devbox inside the computed environment via a generated run script that eval's a command beginning with the literal string "devbox". This required the binary to be named exactly "devbox" and resolvable on PATH; any other name (e.g. a renamed or versioned install) broke services commands with "devbox: command not found". Use os.Executable() to reference the currently running binary (shell- quoted so paths with spaces survive the eval), falling back to "devbox" only if the executable path can't be determined. Fixes #1321.
|
@claude please review this PR for correctness, and flag anything that would block merging. |
|
Claude finished @mikeland73's task in 2m 29s —— View job Review:
|
Use shellescape.Quote (already used in shell.go) instead of strconv.Quote for the devbox executable path. The path is eval'd by a POSIX sh run script, and strconv.Quote emits Go-style \uXXXX escapes that the shell does not interpret inside double quotes, so a binary living under a non-ASCII path would break. shellescape.Quote produces POSIX single- quoted output that round-trips correctly for spaces, unicode, and shell metacharacters. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BQ4KvbTQb7oJ2M3tc79DuG
|
Reviewed for correctness. Summary: I believe this is correct and I don't see anything that blocks merging. Details below, including one behavioral note worth a maintainer's eye and one hardening change I just pushed. Correctness
Behavioral note (not a blocker)Re-invoking Hardening pushed (
|
Summary
Fixes #1321.
devbox services start|stop|ls|restart(and the non-current-shell path ofdevbox services up) work by re-invoking devbox inside the computed environment.runDevboxServicesScriptbuilds a command and hands it toRunScript, which writes a small script thatevals the command. The command began with the hard-coded string"devbox":So the generated script effectively runs
eval "devbox services ...", which requires the binary to be named exactlydevboxand be resolvable onPATH. If the binary is installed or renamed to anything else (a versioned install, a wrapper,devbox-cli, etc.), services commands fail withdevbox: command not found.This was the only real self-invocation of the binary — the process-compose manager already shells out via
processComposeConfig.BinPath, and every otherdevbox ...occurrence in the services code is user-facing help text.Fix
Reference the currently running binary via
os.Executable()instead of the literal"devbox". The path is shell-quoted (viastrconv.Quote, matching how the surrounding code already quotes arguments before they areeval'd) so it survives the eval even if it contains spaces. If the executable path can't be determined, it falls back to"devbox"— the previous PATH-lookup behavior.This mirrors the existing use of
os.Executable()ininternal/devbox/pure_shell.go.How was it tested?
go build ./...— clean.go vet ./internal/devbox/— clean.gofmt— no diffs.TestDevboxBinaryForSelfInvocationininternal/devbox/services_test.go, which asserts the helper returns the shell-quoted path to the running binary rather than the literal"devbox". It passes:cc @mikeland73 (issue reporter)
Community Contribution License
All community contributions in this pull request are licensed to the project
maintainers under the terms of the
Apache 2 License.
By creating this pull request, I represent that I have the right to license the
contributions to the project maintainers under the Apache 2 License as stated in
the
Community Contribution License.
🤖 Generated with Claude Code
https://claude.ai/code/session_01BQ4KvbTQb7oJ2M3tc79DuG
Generated by Claude Code