Skip to content

fix(plugins): quote path env vars in service commands so spaces in project dir work - #2960

Merged
mikeland73 merged 1 commit into
mainfrom
claude/focused-goldberg-vspngu
Sep 14, 2026
Merged

mikeland73 merged 1 commit into
mainfrom
claude/focused-goldberg-vspngu

Conversation

@mikeland73

Copy link
Copy Markdown
Collaborator

Summary

Fixes #2631.

Several builtin plugins reference an absolute project path in their process-compose service command without wrapping it in double quotes:

Plugin command (before)
apache apachectl start -f $HTTPD_CONFDIR/httpd.conf ..., tail -f $HTTPD_ERROR_LOG_FILE, tail -f $HTTPD_ACCESS_LOG_FILE
caddy caddy run --config=$CADDY_CONFIG
php php-fpm -y {{ .DevboxDir }}/php-fpm.conf --nodaemonize
redis redis-server $REDIS_CONF --port $REDIS_PORT
valkey valkey-server $VALKEY_CONF --port $VALKEY_PORT

Each of these variables/templates expands to the project's absolute path (for example $CADDY_CONFIG{{ .DevboxDir }}/Caddyfile, $REDIS_CONF{{ .DevboxDir }}/redis.conf). An unquoted reference is word-split by the shell whenever the project directory contains a space, so the service fails to start. This is the same class of bug as the init_hook fix in #2876 — now applied to the plugin service commands that run under devbox services.

Fix

Wrap each path reference in double quotes, matching the pattern the postgresql plugin already uses (pg_isready -p "${PGPORT:-5432}" and -k "$PGHOST"). Ports and other non-path values are left unquoted. After the fix, e.g.:

command: "caddy run --config=\"$CADDY_CONFIG\""
command: "php-fpm -y \"{{ .DevboxDir }}/php-fpm.conf\" --nodaemonize"

The affected plugins' version fields are bumped, consistent with how prior plugin behavior changes are versioned.

The mariadb, mysql, and nginx plugins have the same unquoted-path pattern in their service commands, but they currently have other in-flight PRs touching those exact files (#2906, #2911, #2909). They were intentionally left out of this PR to avoid conflicts and can be quoted in those PRs or a small follow-up.

How was it tested?

  • Added plugins/service_command_quoting_test.go, which scans every builtin plugin's process-compose.yaml and asserts that templated paths ({{ ... }}) and known path-bearing env vars in service commands are quoted. It reuses the shell-quoting model from the existing init_hook_quoting_test.go. Verified it fails on the old (unquoted) content and passes on the fix.
  • go test ./plugins/ ./internal/plugin/, go vet ./plugins/, and gofmt are clean.

cc @arent-groebner — thanks for the report.

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 by Claude Code

…oject dir work

Several builtin plugins reference an absolute project path in their
process-compose service command without wrapping it in double quotes:

| Plugin | command (before) |
| --- | --- |
| apache | apachectl start -f $HTTPD_CONFDIR/httpd.conf ...; tail -f $HTTPD_ERROR_LOG_FILE |
| caddy  | caddy run --config=$CADDY_CONFIG |
| php    | php-fpm -y {{ .DevboxDir }}/php-fpm.conf --nodaemonize |
| redis  | redis-server $REDIS_CONF --port $REDIS_PORT |
| valkey | valkey-server $VALKEY_CONF --port $VALKEY_PORT |

These variables/templates expand to the project's absolute path (for
example $CADDY_CONFIG -> "{{ .DevboxDir }}/Caddyfile"), so an unquoted
reference is word-split by the shell whenever the project directory
contains a space and the service fails to start. This is the same class
of bug as the init_hook fix in #2876, now applied to service commands.

Wrap each path reference in double quotes, matching the pattern the
postgresql plugin already uses (`-k "$PGHOST"`). Ports and other
non-path values are left unquoted. The affected plugins' version fields
are bumped, consistent with how prior plugin behavior changes are
versioned.

Adds plugins/service_command_quoting_test.go, which scans every builtin
plugin's process-compose.yaml and asserts that templated paths and known
path-bearing env vars in service commands are quoted. It fails on the old
(unquoted) content and passes on the fix.

Fixes #2631
Copilot AI lite review requested due to automatic review settings August 18, 2026 14:17

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@savil
savil marked this pull request as draft September 2, 2026 22:13
@mikeland73

Copy link
Copy Markdown
Collaborator Author

@claude please review this PR for correctness, and flag anything that would block merging.

@claude

claude Bot commented Sep 14, 2026

Copy link
Copy Markdown

Claude finished @mikeland73's task in 2m 57s —— View job


Review complete ✅

  • Gather context (read diff, changed files, CLAUDE.md)
  • Review correctness of quoting fixes in each plugin
  • Check version bumps are correct/consistent
  • Review new test file plugins/service_command_quoting_test.go
  • Check for missed instances (mariadb/mysql/nginx explicitly excluded — verify reasoning)
  • Post final review

Nothing here blocks merging. This is a solid, well-scoped fix. Details below.

Correctness of the quoting fixes

Diffed each affected process-compose.yaml against the pre-fix content and confirmed the quoting is correct in every case:

  • plugins/apache/process-compose.yaml: "$HTTPD_CONFDIR/httpd.conf", "$HTTPD_ERROR_LOG_FILE", "$HTTPD_ACCESS_LOG_FILE" — all correctly quoted; $HTTPD_PORT (a port, not a path) intentionally left unquoted, consistent with the stated scope.
  • plugins/caddy/process-compose.yaml: --config="$CADDY_CONFIG" — correct.
  • plugins/php/process-compose.yaml: "{{ .DevboxDir }}/php-fpm.conf" — correct.
  • plugins/redis/process-compose.yaml and plugins/valkey/process-compose.yaml: config path quoted, port left bare — correct.

Version bumps

Verified each bump against the pre-PR value (patch bumps, as claimed):
apacheHttpd.json 0.0.2→0.0.3, caddy.json 0.0.3→0.0.4, php.json 0.0.3→0.0.4, redis.json 0.0.2→0.0.3, valkey.json 0.0.1→0.0.2.

One clarification worth noting in the PR description (not a blocker): internal/plugin/plugin.go's shouldCreateFile always recreates files under the hidden .devbox dir (which is where the generated process-compose.yaml lives, e.g. .devbox/virtenv/<plugin>/process-compose.yaml), regardless of plugin version. So this fix will take effect for existing users' installed plugins even without the version bump — the bump is for consistency/traceability, not a functional requirement for the fix to apply.

Test coverage

plugins/service_command_quoting_test.go correctly reuses the vetted shellQuotedPositions/templateIndices shell-quoting model from init_hook_quoting_test.go (existing, exercised logic), and adds:

  • TestServiceCommandTemplatePathsAreQuoted — generically checks every builtin plugin's service commands for unquoted {{ ... }} templates.
  • TestServiceCommandEnvPathsAreQuoted — checks a maintained allowlist of path-bearing env vars (HTTPD_CONFDIR, HTTPD_ERROR_LOG_FILE, HTTPD_ACCESS_LOG_FILE, CADDY_CONFIG, PGHOST, REDIS_CONF, VALKEY_CONF) per file.

Both are well-targeted and match the actual fix. Note the env-var test is opt-in per plugin (a new plugin with an unquoted path env var wouldn't be caught automatically) — the template-based test doesn't have this gap since it scans all plugins generically. Minor, not a blocker.

I confirmed via git show on the parent commit that this file's pre-fix content matched what the PR description claims (e.g. apache's -f $HTTPD_CONFDIR/httpd.conf was indeed unquoted).

I wasn't able to execute go build/go test/go vet in this sandbox (tool invocations required approval that wasn't available), so I relied on careful static review of the YAML and test logic instead of confirming a green test run directly.

mariadb / mysql / nginx exclusion

Confirmed by grepping all builtin process-compose.yaml files: these three plugins do have the same unquoted-path pattern (e.g. mariadbd --log-error=$MYSQL_HOME/mysql.log, tail -f $NGINX_PATH_PREFIX/error.log), and are correctly left out of this PR's scope per the description (other in-flight PRs #2906/#2911/#2909 touch those files). No other plugins were missed.

Minor, pre-existing, out of scope

plugins/apache/process-compose.yaml's echo line has a stray \ (backslash-space) before http://localhost:... inside a double-quoted string — harmless (prints a literal backslash in the startup message) and predates this PR, so not something this fix needs to address.

Copy link
Copy Markdown
Collaborator Author

Focusing on merge-readiness here (a detailed line-by-line correctness review is already running separately in this thread):

CI: green. On the head commit 2eb2f1c, cli-tests (run #8130) and Random Reviewer Assignment both completed with success. There are no failing checks. (The combined status API reads empty because these report as Actions check-runs, not legacy commit statuses.)

The one thing blocking merge is the draft state. This PR was converted to a draft (by @savil on Sep 2), so GitHub won't allow merging until it's marked Ready for review. There are no merge conflicts. Per my instructions I've left it as a draft and won't flip it to ready without your go-ahead — say the word and I will.

Minor, non-blocking: the branch is ~10 commits behind main (no conflict). Happy to update it if you'd like CI to re-run against the current base before merging.

Correctness (short version): the diff only wraps absolute-path env vars / templates in double quotes within each plugin's process-compose service command (mirroring the postgresql plugin's existing -k "$PGHOST"); ports and non-path values are left unquoted. go test ./plugins/ passes locally, and the added service_command_quoting_test.go fails on the old unquoted content and passes on the fix, so it guards the regression.


Generated by Claude Code

@mikeland73 mikeland73 added the ready for human review Automated review passed; needs a maintainer to review and merge label Sep 14, 2026
@mikeland73
mikeland73 marked this pull request as ready for review September 14, 2026 16:19
@mikeland73
mikeland73 merged commit 0e00c19 into main Sep 14, 2026
29 checks passed
@mikeland73
mikeland73 deleted the claude/focused-goldberg-vspngu branch September 14, 2026 16:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready for human review Automated review passed; needs a maintainer to review and merge

Development

Successfully merging this pull request may close these issues.

Workspaces with blanks in pathnames are not properly handled

3 participants