Skip to content

Fix SSH alias path not forwarded to remote when defined as a separate config key#6274

Merged
swissspidy merged 2 commits intomainfrom
copilot/fix-remote-webhost-alias
Mar 16, 2026
Merged

Fix SSH alias path not forwarded to remote when defined as a separate config key#6274
swissspidy merged 2 commits intomainfrom
copilot/fix-remote-webhost-alias

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 15, 2026

When two aliases share the same SSH host but differ only by path, both resolve to the same WordPress instance — the remote server's global default path. Aliases like:

@prod:
  ssh: myhost
  path: /var/www/production

@staging:
  ssh: myhost
  path: /var/www/staging

…both end up running against /var/www/production.

Root cause (two bugs in Runner::run_ssh_command())

1. Wrong JSON key in WP_CLI_RUNTIME_ALIAS

The alias was serialized without the @ prefix:

{"prod": {"path": "/var/www/production"}}

But Configurator::get_runtime_aliases() matches against ALIAS_REGEX = ^@[A-Za-z0-9-_\.\-]+$, so the key is never recognized and an empty array is returned — causing get_aliases() to suppress the file-based aliases entirely.

2. Remote wp invocation missing @ prefix

The remote command was built as wp prod option get blogname instead of wp @prod option get blogname, so the remote Runner never treated prod as an alias at all.

Changes

  • Runner.php: Prefix the WP_CLI_RUNTIME_ALIAS JSON key with @ and use @{$this->alias} in the remote command string so the remote process correctly resolves the alias and its associated path.
  • aliases.feature: Strengthen the existing "separate path line" scenario to assert wp @foo appears in the generated SSH command; add a new scenario verifying that two aliases with the same SSH host but different paths produce distinct remote commands.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • a85a96.example.com
    • Triggering command: /usr/bin/php /usr/bin/php /home/REDACTED/work/wp-cli/wp-cli/bin/../php/boot-fs.php core install-network --title=WP CLI Network --subdomains=1 ackback.php ossil list fossil de/node/bin/git git bran�� ntegration-cache--point=100 --no-color ossil -v sh tnet/tools/php fossil (dns block)
  • c63e99.example.com
    • Triggering command: /usr/bin/php /usr/bin/php /home/REDACTED/work/wp-cli/wp-cli/bin/../php/boot-fs.php core install-network --title=WP CLI Network --subdomains=1 sh k/_temp/ghcca-node/node/bin/sh P_CLI\Tests\Contsh install de/node/bin/sh sh k/wp�� 4e74.39492867 create /home/REDACTED/.dotnet/tools/sh --dbuser=wp_cli_sh --dbpass=passwor-c --dbhost=localhocp -r '/tmp/wp-cli-test-core-install-cache-6.9.4/install_acfe23c48ba3fa81d7f3142--title=WP CLI Site sh (dns block)
  • example.com
    • Triggering command: /usr/bin/php php vendor/bin/phpunit --color=always --bootstrap ./vendor/wp-cli/wp-cli-tests/tests/bootstrap.php (dns block)
    • Triggering command: /usr/bin/php /usr/bin/php /home/REDACTED/work/wp-cli/wp-cli/bin/../php/boot-fs.php core install --url=REDACTED --title=WP CLI Site --admin_user=admin --admin_email=admin@example.com --admin_password=password1 --skip-email (dns block)
    • Triggering command: /usr/bin/php /usr/bin/php /home/REDACTED/work/wp-cli/wp-cli/bin/../php/boot-fs.php core install --url=REDACTED --title=WP CLI Site --admin_user=admin --admin_email=admin@example.com --admin_password=password1 --skip-email ./php/commands/s--name /usr/bin/php8.5 -d d�� -d asp_tags=Off -d short_open_tag=Off it -n -l ./php/WP_CLI/Traverser/RecursiveDataStructureTra-ppassword1 /usr/bin/php8.5 (dns block)
  • host
    • Triggering command: /usr/bin/ssh ssh -T -vvv user@host env WP_CLI_RUNTIME_ALIAS='{"@foo":{"path":"\/path\/to\/wordpress"}}' wp @foo --debug --version alias g=Off ng=E_ALL -nxv (dns block)
    • Triggering command: /usr/bin/ssh ssh -T -vvv user@host env WP_CLI_RUNTIME_ALIAS='{"@prod":{"path":"\/path\/to\/production"}}' wp @prod --debug --version -remote-webhost-alias (dns block)
    • Triggering command: /usr/bin/ssh ssh -T -vvv user@host env WP_CLI_RUNTIME_ALIAS='{"@staging":{"path":"\/path\/to\/staging"}}' wp @staging --debug --version admin' --admin_email='admin@example.com' --admin_password='password1' --skip-email -d short_open_tag=Off p/bin/php -n -l ./php/WP_CLI/Bootstrap/InitializeContexts.php 402.php' an alias ABLE_WP_CRON', true ); } /bin/sh (dns block)
  • httpbin.org
    • Triggering command: /usr/bin/php /usr/bin/php /home/REDACTED/work/wp-cli/wp-cli/bin/../php/boot-fs.php http-methods-test --debug=http k/wp�� aafd77980.38088829//wp-content/mu-plugins' db vendor/bin/sh de/node/bin/sh ssh /usr/bin/tput stty bin/�� n/sh tput (dns block)
  • nosuchhost_asdf_asdf_asdf.com
    • Triggering command: /usr/bin/php php vendor/bin/phpunit --color=always --bootstrap ./vendor/wp-cli/wp-cli-tests/tests/bootstrap.php (dns block)
  • proxyhost
    • Triggering command: /usr/bin/ssh ssh -vvv -W [host]:22 proxyhost -h -o which 4 features/bootstrvendor/bin/behat features/class-w--snippets-for=WP_CLI\Tests\Context\FeatureContext which mari�� features/cli-che--tags=~@less-than-wp-5.5&&~@less-than-wp-6.1&&~@less-than-php-7.4&&~@less-than-sh rue ); } mposer/vendor/bi--name features/commandmysql features/config.--version features/context.feature an-php-8.2&&~@less-than-php-8&&~@broken&&~@requifeatures/cli-info.feature (dns block)
    • Triggering command: /usr/bin/ssh ssh -vvv -W [host]:22 proxyhost (dns block)
    • Triggering command: /usr/bin/ssh ssh -vvv -W [host]:22 proxyhost 9bdd22ae7.85276690/foo/wp-content/mu-plugins' which bin/sh k/wp-cli/wp-cli//usr/bin/php (dns block)
  • wordpress
    • Triggering command: /usr/bin/ssh ssh -T -vvv wordpress cd '/my/path'; wp --debug --version text-logger.php eval '' which k/wp-cli/wp-cli/bin/sh ch mysql sh mposer/vendor/bi--require=doobie/*.php mysql bin/�� rgo/bin/sh sh mposer/vendor/bin/sh u-plugins' sh cal/bin/sh sh (dns block)
    • Triggering command: /usr/bin/ssh ssh -o ConnectTimeout=5 -T -vvv wordpress wp --debug --version info de/node/bin/sh -run--69b6ba437csh tput bin/sh sh bin/�� --require=test-cache-config.php test-cache-config nfig/composer/vendor/bin/sh k/wp-cli/wp-cli/sh sh ); sh (dns block)
    • Triggering command: /usr/bin/ssh ssh -o ConnectTimeout=5 -o ServerAliveInterval=10 -T -vvv wordpress wp --debug --version tion_exists( "media_handle_upload" ) ); -test-run--69b6bsh y size 2>/dev/nu/home/REDACTED/work/wp-cli/wp-cli/bin/wp ut sh bin/�� -menu-order.php test-skip-prompt (dns block)
  • wp-cli.org
    • Triggering command: /usr/bin/php /usr/bin/php /home/REDACTED/work/wp-cli/wp-cli/bin/../php/boot-fs.php package install /tmp/wp-cli-test-run--69b6b9f4d29628.38709557/override ae2def sh il cli alias rgo/bin/sh sh bin/�� k/wp-cli/wp-cli/HEAD alias /usr/bin/sh --raw --format=json (dns block)
    • Triggering command: /usr/bin/php /usr/bin/php /home/REDACTED/work/wp-cli/wp-cli/bin/../php/boot-fs.php package install /tmp/wp-cli-test-run--69b6b9f60611d8.16166858/override che-6.9.4/install_34f3da9689642b02bfdc2a3bb7dc5325/wp-config.php che-6.9.4/install_34f3da9689642b02bfdc2a3bb7dc5325/wp-content 33f2.48398847 -W [host]:22 /home/REDACTED/worlist sh /hom�� b4c4.01786977 option /home/REDACTED/work/wp-cli/wp-cli/bin/wp home gins mposer/vendor/bi--require=override/override.php wp (dns block)
    • Triggering command: /usr/bin/php /usr/bin/php /home/REDACTED/work/wp-cli/wp-cli/bin/../php/boot-fs.php package install wp-cli/cache-command /usr/local/sbin/-v git svn -cli-composer-losvn --format=%H ndor/bin/fossil stty -a nfig/composer/vendor/bin/hg stty bin/git vendor/bin/sh sh rgo/bin/git fossil (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Original prompt

This section details on the original issue you should resolve

<issue_title>Possible to make different aliases to same remote webhost account with only different paths on remote?</issue_title>
<issue_description>## Documentation does not answer my use case yet

Server side

Accessing production vs. staging in the shell on the server (via SSH)

$ ssh dd

# I'm now on my webhost, executing commands there.

$ wp @dd option get blogname
DD

$ wp @dds option get blogname
DDS
  • ✅ The different aliases return different results, each corresponding to their respective WordPress instance.

~/.wp-cli/config.yml (Webhost)

# Global parameter defaults
path: /data/web/•••/html/apps/dd/

# Aliases
@dd:
  path: /data/web/•••/html/apps/dd/

@dds:
  path: /data/web/•••/html/apps/dd-staging/

Client side (Mac)

Client side aliases to access different WP instances (production and staging-subdomain) on the very same remote webhost and very same user account there

  • I'm now on my Mac.
  • Running my local wp-cli which connects to the remote wp-cli.
    • This worked fine when I only had 1 WordPress instance on that webhost account.
  • For a while I used a production and a staging server with aliases on the server, as shown in the previous section. Worked fine all time.
    • Now I had set up two aliases on my client side machine corresponding to those two remote instances too.
    • ❌ But both aliases seem to resolve to the same WP instance on the remote!
$ wp @dd option get blogname
DD

$ wp @dds option get blogname
DD
  • ❌ The last command should have returned "DDS" but returned "DD".
    • I have my dounbts that the aliases resolve correctly.
    • See my client config:

~/.wp-cli/config.yml (Mac)

# Global parameter defaults
path: ~/Web

@dd:
  ssh: dd
  path: /data/web/•••/html/apps/dd/
@dds:
  ssh: dd
  path: /data/web/•••/html/apps/dd-staging/

Questions

  1. Is it a problem that I use the same alias names client side as server side?

    • I rather rule that out.
    • I temporarily set my client side aliases to @d and @ds respectively, but it made no difference.
    • Still got the same blogname for both, depsite them being different in reality.
  2. Is the same SSH connection but different paths not enough to constitute two indeed different valid aliases?</issue_description>

Comments on the Issue (you are @copilot in this section)

@danielbachhuber Hey @porg,

In honesty, I wrote the aliases implementation and have no memory to how it works. We'll see if some other contributor can help out.</comment_new>


💬 Send tasks to Copilot coding agent from Slack and Teams to turn conversations into code. Copilot posts an update in your thread when it's finished.

…nfig key

Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix multiple aliases for remote webhost account Fix SSH alias path not forwarded to remote when defined as a separate config key Mar 15, 2026
Copilot AI requested a review from swissspidy March 15, 2026 14:00
@codecov
Copy link
Copy Markdown

codecov bot commented Mar 15, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@swissspidy swissspidy marked this pull request as ready for review March 15, 2026 15:22
@swissspidy swissspidy requested a review from a team as a code owner March 15, 2026 15:22
Copilot AI review requested due to automatic review settings March 15, 2026 15:22
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes remote alias resolution over SSH when aliases share the same SSH host but differ by path, ensuring the correct WordPress instance is targeted on the remote machine.

Changes:

  • Fix WP_CLI_RUNTIME_ALIAS serialization to use @<alias> keys so Configurator::get_runtime_aliases() recognizes them.
  • Fix the remote wp invocation to pass the alias as @<alias> so the remote Runner actually applies the alias config.
  • Extend Behat coverage to assert the @-prefixed alias is present in the SSH command and that two same-host/different-path aliases produce distinct remote commands.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
php/WP_CLI/Runner.php Ensures runtime alias env JSON and remote wp invocation both use @<alias> so the remote process resolves the alias (including path).
features/aliases.feature Adds/strengthens scenarios to validate correct alias forwarding and distinct per-alias remote commands when only path differs.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

@swissspidy swissspidy merged commit 574199c into main Mar 16, 2026
73 checks passed
@swissspidy swissspidy deleted the copilot/fix-remote-webhost-alias branch March 16, 2026 07:26
@swissspidy swissspidy added this to the 3.0.0 milestone Mar 16, 2026
swissspidy added a commit to apermo/wp-cli that referenced this pull request Mar 16, 2026
… config key (wp-cli#6274)

* Initial plan

* Fix SSH alias path not forwarded to remote when path is a separate config key

Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com>
swissspidy added a commit that referenced this pull request Mar 16, 2026
…6270)

* fix(context): resolve admin user dynamically

Replace hardcoded user ID 1 fallback in Admin
context with smart user resolution. On multisite,
queries get_super_admins() to find a valid super
admin. On single site, queries for the first user
with the administrator role. Emits a clear error
if no suitable user is found.

Fixes #6269

* fix(context): optimize query and add test cases

Use get_users() with login__in for single DB query
instead of looping get_user_by(). Add single-site
error case test. Replace wp super-admin commands
with direct option manipulation in tests.

* fix(context): fix linting issues

Use single quotes for strings per PHPCS rules.
Fix gherkin use-and lint violations by replacing
consecutive When steps with And.

* fix(context): address review feedback

Revert multisite super admin lookup from get_users()
back to foreach + get_user_by('login') loop because
get_users() only fetches users on the current site
but a super admin might not be a member of any site.

Add debug logging after resolving admin user ID.

* fix(context): use instanceof for type safety

* Fix autoloader priority: locally installed packages now fully override phar-bundled versions (#6218)

Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Pascal Birchler <pascalb@google.com>

* Add environment variable configuration support to wp-cli.yml (#6169)

Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Pascal Birchler <pascalb@google.com>

* Autocomplete `--url` (#5704)

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Pascal Birchler <pascalb@google.com>
Co-authored-by: Pascal Birchler <pascal.birchler@gmail.com>

* Add WP-CLI handbook link to `wp help` output (#6273)

* Initial plan

* Add WP-CLI handbook URL reference to wp help output

Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com>

* Update file(s) from wp-cli/.github

* Update file(s) from wp-cli/.github

* Fix SSH alias path not forwarded to remote when defined as a separate config key (#6274)

* Initial plan

* Fix SSH alias path not forwarded to remote when path is a separate config key

Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com>

* Fix: forward active alias to runcommand subprocess (#6272)

Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>

* Fix vagrant SSH strict host key checking failure (#6275)

* Initial plan

* Fix vagrant SSH strict host key checking failure

When ssh: vagrant is configured and vagrant ssh-config is parsed,
add -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null to
the SSH command to match what vagrant itself sets. This prevents
failures when the vagrant VM has been recreated and has a different
host key than what is stored in ~/.ssh/known_hosts.

Adds a Behat test scenario to verify the fix.

Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Apply suggestion from @swissspidy

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com>
Co-authored-by: Pascal Birchler <pascalb@google.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Add optional `$newline` parameter to `WP_CLI::log()` and `WP_CLI::line()` (#6276)

* Initial plan

* Add optional $newline parameter to WP_CLI::log(), WP_CLI::line(), and logger info() methods

Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com>

* Undo Base class change

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com>
Co-authored-by: Pascal Birchler <pascalb@google.com>

* Refactor: remove unused imports (#6277)

* Harden some tests on macOS

* Update tests

---------

Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Pascal Birchler <pascalb@google.com>
Co-authored-by: Ian Dunn <ian@iandunn.name>
Co-authored-by: Pascal Birchler <pascal.birchler@gmail.com>
Co-authored-by: swissspidy <swissspidy@users.noreply.github.com>
Co-authored-by: Sören Wünsch <soerenwrede@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Possible to make different aliases to same remote webhost account with only different paths on remote?

3 participants